1 /*
2 * Copyright (c) 2013-2025 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
62 #include <skywalk/lib/net_filter_event.h>
63 #endif /* defined(SKYWALK) */
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 #include <kern/socket_flows.h>
80
81 #include <net/sockaddr_utils.h>
82 #include <net/trie_utility.h>
83
84 /*
85 * NECP - Network Extension Control Policy database
86 * ------------------------------------------------
87 * The goal of this module is to allow clients connecting via a
88 * policy file descriptor to create high-level policy sessions, which
89 * are ingested into low-level kernel policies that control and tag
90 * traffic at the application, socket, and IP layers.
91 *
92 * ------------------------------------------------
93 * Sessions
94 * ------------------------------------------------
95 * Each session owns a list of session policies, each of which can
96 * specify any combination of conditions and a single result. Each
97 * session also has a priority level (such as High, Default, or Low)
98 * which is requested by the client. Based on the requested level,
99 * a session order value is assigned to the session, which will be used
100 * to sort kernel policies generated by the session. The session client
101 * can specify the sub-order for each policy it creates which will be
102 * used to further sort the kernel policies.
103 *
104 * Policy fd --> 1 necp_session --> list of necp_session_policy structs
105 *
106 * ------------------------------------------------
107 * Kernel Policies
108 * ------------------------------------------------
109 * Whenever a session send the Apply command, its policies are ingested
110 * and generate kernel policies. There are two phases of kernel policy
111 * ingestion.
112 *
113 * 1. The session policy is parsed to create kernel policies at the socket
114 * and IP layers, when applicable. For example, a policy that requires
115 * all traffic from App1 to Pass will generate a socket kernel policy to
116 * match App1 and mark packets with ID1, and also an IP policy to match
117 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
118 * resulting kernel policies are added to the global socket and IP layer
119 * policy lists.
120 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
121 * || ||
122 * \/ \/
123 * necp_kernel_socket_policies necp_kernel_ip_output_policies
124 *
125 * 2. Once the global lists of kernel policies have been filled out, each
126 * list is traversed to create optimized sub-lists ("Maps") which are used during
127 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
128 * which hashes incoming packets based on marked socket-layer policies, and removes
129 * duplicate or overlapping policies. Socket policies are sent into two maps,
130 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
131 * The app layer map is used for policy checks coming in from user space, and is one
132 * list with duplicate and overlapping policies removed. The socket map hashes based
133 * on app UUID, and removes duplicate and overlapping policies.
134 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
135 * |-> necp_kernel_socket_policies_map
136 *
137 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
138 *
139 * ------------------------------------------------
140 * Drop All Level
141 * ------------------------------------------------
142 * The Drop All Level is a sysctl that controls the level at which policies are allowed
143 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
144 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
145 * by a session with a priority level better than (numerically less than) the
146 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
147 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
148 * session orders to be dropped.
149 */
150
151 u_int32_t necp_drop_all_order = 0;
152 u_int32_t necp_drop_all_level = 0;
153
154 u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
155 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
156 u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
157 u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
158 u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
159
160 u_int32_t necp_drop_unentitled_order = 0;
161 #ifdef XNU_TARGET_OS_WATCH
162 u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
163 #else // XNU_TARGET_OS_WATCH
164 u_int32_t necp_drop_unentitled_level = 0;
165 #endif // XNU_TARGET_OS_WATCH
166
167 u_int32_t necp_drop_management_order = 0;
168 u_int32_t necp_drop_management_level = NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL;
169
170 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
171
172 os_log_t necp_log_handle = NULL;
173 os_log_t necp_data_trace_log_handle = NULL;
174
175 u_int32_t necp_session_count = 0;
176 u_int32_t necp_trie_count = 0;
177
178 static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
179 struct necp_session_policy, NET_KT_DEFAULT);
180 static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
181 struct necp_kernel_socket_policy, NET_KT_DEFAULT);
182 static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
183 struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
184
185 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
186 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
187 LIST_INSERT_HEAD((head), elm, field); \
188 } else { \
189 LIST_FOREACH(tmpelm, head, field) { \
190 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
191 LIST_INSERT_AFTER(tmpelm, elm, field); \
192 break; \
193 } \
194 } \
195 } \
196 } while (0)
197
198 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
199 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
200 LIST_INSERT_HEAD((head), elm, field); \
201 } else { \
202 LIST_FOREACH(tmpelm, head, field) { \
203 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))) { \
204 LIST_INSERT_AFTER(tmpelm, elm, field); \
205 break; \
206 } \
207 } \
208 } \
209 } while (0)
210
211 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
212 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))) { \
213 LIST_INSERT_HEAD((head), elm, field); \
214 } else { \
215 LIST_FOREACH(tmpelm, head, field) { \
216 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))) { \
217 LIST_INSERT_AFTER(tmpelm, elm, field); \
218 break; \
219 } \
220 } \
221 } \
222 } while (0)
223
224 #define IS_NECP_ROUTE_RULE_DENY(x) ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE)
225
226 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x) (IS_NECP_ROUTE_RULE_DENY(x) || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
227
228 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x000001
229 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x000002
230 #define NECP_KERNEL_CONDITION_PROTOCOL 0x000004
231 #define NECP_KERNEL_CONDITION_LOCAL_START 0x000008
232 #define NECP_KERNEL_CONDITION_LOCAL_END 0x000010
233 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x000020
234 #define NECP_KERNEL_CONDITION_REMOTE_START 0x000040
235 #define NECP_KERNEL_CONDITION_REMOTE_END 0x000080
236 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x000100
237 #define NECP_KERNEL_CONDITION_APP_ID 0x000200
238 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x000400
239 #define NECP_KERNEL_CONDITION_DOMAIN 0x000800
240 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x001000
241 #define NECP_KERNEL_CONDITION_POLICY_ID 0x002000
242 #define NECP_KERNEL_CONDITION_PID 0x004000
243 #define NECP_KERNEL_CONDITION_UID 0x008000
244 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x010000 // Only set from packets looping between interfaces
245 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x020000
246 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x040000
247 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 0x080000
248 #define NECP_KERNEL_CONDITION_AGENT_TYPE 0x100000
249 #define NECP_KERNEL_CONDITION_HAS_CLIENT 0x200000
250 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS 0x400000
251 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS 0x800000
252 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY 0x1000000
253 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY 0x2000000
254 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY 0x4000000
255 #define NECP_KERNEL_CONDITION_SDK_VERSION 0x8000000
256 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x10000000
257 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 0x20000000
258 #define NECP_KERNEL_CONDITION_IS_LOOPBACK 0x40000000
259 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY 0x80000000
260 #define NECP_KERNEL_CONDITION_SCHEME_PORT 0x100000000
261 #define NECP_KERNEL_CONDITION_DOMAIN_FILTER 0x200000000
262 #define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT 0x400000000
263 #define NECP_KERNEL_CONDITION_EXACT_DOMAIN 0x800000000
264 #define NECP_KERNEL_CONDITION_REAL_UID 0x1000000000
265 #define NECP_KERNEL_CONDITION_URL 0x2000000000
266 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS 0x4000000000
267
268 #define NECP_MAX_POLICY_RESULT_SIZE 512
269 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
270 #define NECP_MAX_CONDITIONS_ARRAY_SIZE 4096
271 #define NECP_MAX_POLICY_LIST_COUNT 1024
272
273 #define NECP_MAX_DOMAIN_FILTER_SIZE 65536 // Allows room for 100K domains
274 #define NECP_MAX_DOMAIN_TRIE_SIZE (1024 * 512) // Allows 5000+ domains
275
276 typedef enum {
277 NECP_BYPASS_TYPE_NONE = 0,
278 NECP_BYPASS_TYPE_INTCOPROC = 1,
279 NECP_BYPASS_TYPE_LOOPBACK = 2,
280 NECP_BYPASS_TYPE_DROP = 3, // Drop now without hitting necp policies
281 } necp_socket_bypass_type_t;
282
283 // Cap the policy size at the max result + conditions size, with room for extra TLVs
284 #define NECP_MAX_POLICY_SIZE (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
285
286 struct necp_service_registration {
287 LIST_ENTRY(necp_service_registration) session_chain;
288 LIST_ENTRY(necp_service_registration) kernel_chain;
289 u_int32_t service_id;
290 };
291
292 struct necp_domain_filter {
293 LIST_ENTRY(necp_domain_filter) owner_chain;
294 LIST_ENTRY(necp_domain_filter) chain;
295 u_int32_t id;
296 struct net_bloom_filter *filter;
297 os_refcnt_t refcount;
298 };
299 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
300
301 /*
302 * Filter id space is split between domain bloom filter id and domain trie filter id.
303 * id <= 10000 - bloom filter ids
304 * id > 10000 - trie filter ids
305 */
306 #define NECP_DOMAIN_FILTER_ID_MAX 10000
307 #define NECP_DOMAIN_TRIE_ID_START NECP_DOMAIN_FILTER_ID_MAX
308 #define NECP_IS_DOMAIN_FILTER_ID(id) (id <= NECP_DOMAIN_FILTER_ID_MAX)
309
310 struct necp_domain_trie {
311 LIST_ENTRY(necp_domain_trie) owner_chain;
312 LIST_ENTRY(necp_domain_trie) chain;
313 u_int32_t id;
314 struct necp_domain_trie_request *trie_request;
315 size_t trie_request_size;
316 struct net_trie trie;
317 os_refcnt_t refcount;
318 };
319 static LIST_HEAD(necp_domain_trie_list, necp_domain_trie) necp_global_domain_trie_list;
320
321 struct necp_session {
322 u_int8_t necp_fd_type;
323 u_int32_t control_unit;
324 u_int32_t session_priority; // Descriptive priority rating
325 u_int32_t session_order;
326
327 necp_policy_id last_policy_id;
328
329 decl_lck_mtx_data(, lock);
330
331 bool proc_locked; // Messages must come from proc_uuid
332 uuid_t proc_uuid;
333 int proc_pid;
334
335 bool dirty;
336 LIST_HEAD(_policies, necp_session_policy) policies;
337
338 LIST_HEAD(_services, necp_service_registration) services;
339 struct necp_domain_filter_list domain_filters;
340 struct necp_domain_trie_list domain_tries;
341
342 TAILQ_ENTRY(necp_session) chain;
343 };
344
345 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
346 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
347
348 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
349
350 struct necp_socket_info {
351 pid_t pid;
352 int32_t pid_version;
353 uid_t uid;
354 uid_t real_uid;
355 union necp_sockaddr_union local_addr;
356 union necp_sockaddr_union remote_addr;
357 u_int32_t bound_interface_index;
358 u_int32_t bound_interface_flags;
359 u_int32_t bound_interface_eflags;
360 u_int32_t bound_interface_xflags;
361 u_int32_t traffic_class;
362 u_int16_t protocol;
363 u_int16_t scheme_port;
364 u_int32_t application_id;
365 u_int32_t real_application_id;
366 u_int32_t account_id;
367 u_int32_t drop_order;
368 u_int32_t client_flags;
369 char *domain __null_terminated;
370 char *url __null_terminated;
371 struct soflow_hash_entry *soflow_entry;
372 unsigned is_entitled : 1;
373 unsigned has_client : 1;
374 unsigned has_system_signed_result : 1;
375 unsigned is_platform_binary : 1;
376 unsigned used_responsible_pid : 1;
377 unsigned is_loopback : 1;
378 unsigned real_is_platform_binary : 1;
379 unsigned is_delegated : 1;
380 unsigned is_local : 1;
381 unsigned __pad_bits : 7;
382 };
383
384 static LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
385 static LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
386 static LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
387 &necp_kernel_policy_mtx_attr);
388
389 static LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
390 static LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
391
392 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
393
394 /*
395 * On modification, invalidate cached lookups by bumping the generation count.
396 * Other calls will need to take the slowpath of taking
397 * the subsystem lock.
398 */
399 static volatile int32_t necp_kernel_socket_policies_gencount;
400 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
401 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
402 necp_kernel_socket_policies_gencount = 1; \
403 } \
404 } while (0)
405
406 /*
407 * Drop-all Bypass:
408 * Allow priviledged processes to bypass the default drop-all
409 * via entitlement check. For OSX, since entitlement check is
410 * not supported for configd, configd signing identity is checked
411 * instead.
412 */
413 #define SIGNING_ID_CONFIGD "com.apple.configd"
414 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
415
416 typedef enum {
417 NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
418 NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
419 NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
420 } necp_drop_all_bypass_check_result_t;
421
422 static u_int64_t necp_kernel_application_policies_condition_mask;
423 static size_t necp_kernel_application_policies_count;
424 static u_int64_t necp_kernel_socket_policies_condition_mask;
425 static size_t necp_kernel_socket_policies_count;
426 static size_t necp_kernel_socket_policies_non_app_count;
427 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
428 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
429 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
430 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
431 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
432 static size_t necp_kernel_socket_policies_app_layer_map_count;
433 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_app_layer_map;
434 /*
435 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
436 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
437 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
438 *
439 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
440 */
441
442 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
443 static size_t necp_kernel_ip_output_policies_count;
444 static size_t necp_kernel_ip_output_policies_non_id_count;
445 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
446 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
447 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
448 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
449 static struct necp_kernel_ip_output_policy ** __indexable necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
450 static struct necp_kernel_socket_policy pass_policy =
451 {
452 .id = NECP_KERNEL_POLICY_ID_NO_MATCH,
453 .result = NECP_KERNEL_POLICY_RESULT_PASS,
454 };
455
456 static struct necp_session *necp_create_session(void);
457 static void necp_delete_session(struct necp_session *session);
458
459 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
460 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
461 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
462
463 #define MAX_RESULT_STRING_LEN 64
464 static inline const char * __sized_by(MAX_RESULT_STRING_LEN) necp_get_result_description(char * __sized_by(MAX_RESULT_STRING_LEN) result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
465
466 static struct necp_session_policy *necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *__sized_by(conditions_array_size)conditions_array, u_int32_t conditions_array_size, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, u_int8_t * __sized_by(result_size)result, u_int32_t result_size);
467 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
468 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
469 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
470 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
471 static void necp_policy_apply_all(struct necp_session *session);
472
473 static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement __null_terminated, u_int32_t cond_account_id, char *cond_domain __null_terminated, u_int32_t cond_domain_filter, char *cond_url __null_terminated, 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 * __single 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 __null_terminated, 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, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
474 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
475 static bool necp_kernel_socket_policies_reprocess(void);
476 static bool necp_kernel_socket_policies_update_uuid_table(void);
477 static inline struct necp_kernel_socket_policy * necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
478 struct necp_socket_info *info,
479 necp_kernel_policy_filter *return_filter,
480 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
481 size_t *return_route_rule_id_array_count,
482 size_t route_rule_id_array_count,
483 necp_kernel_policy_result *return_service_action,
484 necp_kernel_policy_service *return_service,
485 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
486 size_t netagent_array_count,
487 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
488 size_t netagent_use_flags_array_count,
489 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
490 u_int32_t num_required_agent_types,
491 proc_t proc,
492 u_int16_t pf_tag,
493 necp_kernel_policy_id *skip_policy_id,
494 struct rtentry *rt,
495 necp_kernel_policy_result *return_drop_dest_policy_result,
496 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
497 u_int32_t *return_flow_divert_aggregate_unit,
498 struct socket *so,
499 int debug);
500 static necp_kernel_policy_id necp_kernel_ip_output_policy_add(necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_kernel_policy_id cond_policy_id, ifnet_t cond_bound_interface, u_int32_t cond_last_interface_index, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
501 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
502 static bool necp_kernel_ip_output_policies_reprocess(void);
503
504 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
505 static bool necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end);
506 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
507 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
508 static bool necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits);
509 static bool necp_addr_is_empty(struct sockaddr *addr);
510 static bool necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index);
511 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
512
513 struct necp_uuid_id_mapping {
514 LIST_ENTRY(necp_uuid_id_mapping) chain;
515 uuid_t uuid;
516 u_int32_t id;
517 os_refcnt_t refcount;
518 u_int32_t table_usecount; // Add to UUID policy table count
519 };
520 static size_t necp_num_uuid_app_id_mappings;
521 static bool necp_uuid_app_id_mappings_dirty;
522 #define NECP_UUID_APP_ID_HASH_SIZE 64
523 static u_long necp_uuid_app_id_hash_mask;
524 static u_long necp_uuid_app_id_hash_num_buckets;
525 static LIST_HEAD(necp_uuid_id_mapping_head, necp_uuid_id_mapping) * __counted_by(necp_uuid_app_id_hash_num_buckets) necp_uuid_app_id_hashtbl, necp_uuid_service_id_list; // App map is real hash table, service map is just mapping
526 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
527 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
528 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
529 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
530
531 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
532 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
533 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
534 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
535 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
536
537 struct necp_string_id_mapping {
538 LIST_ENTRY(necp_string_id_mapping) chain;
539 char *string __null_terminated;
540 necp_app_id id;
541 os_refcnt_t refcount;
542 };
543 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
544 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
545 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
546 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
547
548 static u_int32_t necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter);
549 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
550 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
551
552 static u_int32_t necp_create_domain_trie(struct necp_domain_trie_list *list, struct necp_domain_trie_list *owner_list,
553 struct necp_domain_trie_request *necp_trie_request, size_t necp_trie_request_size);
554 static bool necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id);
555 static void necp_free_domain_trie(struct necp_domain_trie *trie);
556 static struct necp_domain_trie *necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id);
557 static Boolean necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length);
558
559 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
560 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
561
562 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
563
564 static char * __null_terminated necp_create_trimmed_domain(char * __sized_by(length)string, size_t length);
565 static inline int necp_count_dots(char * __sized_by(length)string, size_t length);
566
567 static char * __null_terminated necp_copy_string(char * __sized_by(length)string, size_t length);
568 static bool necp_update_qos_marking(struct ifnet *ifp, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id);
569
570 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
571
572 #define MAX_ROUTE_RULE_INTERFACES 10
573 struct necp_route_rule {
574 LIST_ENTRY(necp_route_rule) chain;
575 u_int32_t id;
576 u_int32_t netagent_id;
577 u_int32_t control_unit;
578 u_int32_t match_netagent_id;
579 u_int32_t effective_type;
580 u_int8_t default_action;
581 u_int8_t cellular_action;
582 u_int8_t wifi_action;
583 u_int8_t wired_action;
584 u_int8_t expensive_action;
585 u_int8_t constrained_action;
586 u_int8_t companion_action;
587 u_int8_t vpn_action;
588 u_int exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
589 u_int8_t exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
590 os_refcnt_t refcount;
591 };
592 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
593 static u_int32_t necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, bool *has_socket_only_actions);
594 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
595 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
596 static bool necp_route_is_allowed(struct rtentry *route, ifnet_t interface, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count,
597 u_int32_t route_rule_id, u_int32_t *interface_type_denied);
598 static uint32_t necp_route_get_netagent(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove);
599 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
600 static uint32_t necp_route_get_flow_divert(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, u_int32_t *flow_divert_aggregate_unit);
601 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
602 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
603
604 #define MAX_AGGREGATE_ROUTE_RULES 16
605 struct necp_aggregate_route_rule {
606 LIST_ENTRY(necp_aggregate_route_rule) chain;
607 u_int32_t id;
608 u_int32_t rule_ids[MAX_AGGREGATE_ROUTE_RULES];
609 };
610 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
611 static u_int32_t necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids);
612
613 // Sysctl definitions
614 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
615 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
616 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
617
618 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
619 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
620 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
621 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
622 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
623 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
624 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
625 SYSCTL_PROC(_net_necp, NECPCTL_DROP_UNENTITLED_LEVEL, drop_unentitled_level, CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_unentitled_level, 0, &sysctl_handle_necp_unentitled_level, "IU", "");
626 SYSCTL_PROC(_net_necp, NECPCTL_DROP_MANAGEMENT_LEVEL, drop_management_level, CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_management_level, 0, &sysctl_handle_necp_management_level, "IU", "");
627 SYSCTL_PROC(_net_necp, NECPCTL_DROP_ALL_LEVEL, drop_all_level, CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_all_level, 0, &sysctl_handle_necp_level, "IU", "");
628 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
629 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_NON_APP_POLICY_COUNT, socket_non_app_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_non_app_count, "");
630 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
631 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
632 SYSCTL_INT(_net_necp, NECPCTL_TRIE_COUNT, trie_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_trie_count, 0, "");
633
634 static struct necp_drop_dest_policy necp_drop_dest_policy;
635 static int necp_drop_dest_debug = 0; // 0: off, 1: match, >1: every evaluation
636 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
637
638 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
639 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
640 0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
641
642 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
643
644 /*
645 * data tracing control -
646 *
647 * necp_data_tracing_level : 1 for brief trace, 2 for policy details, 3 for condition details
648 * necp_data_tracing_port : match traffic with specified port
649 * necp_data_tracing_proto : match traffic with specified protocol
650 * necp_data_tracing_pid : match traffic with specified pid (only applied at socket level)
651 * necp_data_tracing_ifindex : match traffic on specified ifindex
652 * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched. Default is 0 to trace traffic if any specified attributes matched.
653 * data_tracing_session_order : match policies in the specified session - log traffic that hit these policies
654 * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
655 */
656 static int necp_data_tracing_level = 0;
657 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
658
659 static int necp_data_tracing_port = 0;
660 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
661
662 static int necp_data_tracing_proto = 0;
663 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
664
665 static int necp_data_tracing_pid = 0;
666 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
667
668 static int necp_data_tracing_ifindex = 0;
669 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
670
671 static int necp_data_tracing_match_all = 0;
672 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
673
674 static int necp_data_tracing_session_order = 0;
675 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
676
677 static int necp_data_tracing_policy_order = 0;
678 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
679
680 #define NECP_DATA_TRACE_LEVEL_BRIEF 1
681 #define NECP_DATA_TRACE_LEVEL_POLICY 2
682 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
683 #define NECP_DATA_TRACE_LEVEL_DP 4
684
685 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
686 (pid == necp_data_tracing_pid)
687 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
688 (protocol == necp_data_tracing_proto)
689 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
690 (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
691 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
692 (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
693 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
694 (ifindex == necp_data_tracing_ifindex)
695
696 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
697 ((necp_data_tracing_level && \
698 ((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
699 (necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
700 (necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
701 (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)
702
703 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
704 ((necp_data_tracing_level && \
705 ((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
706 (!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
707 (!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
708 (!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)
709
710 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
711 (necp_data_tracing_match_all ? \
712 NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
713 NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
714
715 #define NECP_DATA_TRACE_ON(debug) (debug)
716 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
717 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
718 #define NECP_DATA_TRACE_DP_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_CONDITION)
719
720 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
721
722 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
723 if (NECP_DATA_TRACE_ON(debug)) { \
724 char laddr_str[MAX_IPv6_STR_LEN]; \
725 char raddr_str[MAX_IPv6_STR_LEN]; \
726 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>", \
727 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); \
728 }
729
730 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
731 if (NECP_DATA_TRACE_ON(debug)) { \
732 char laddr_str[MAX_IPv6_STR_LEN]; \
733 char raddr_str[MAX_IPv6_STR_LEN]; \
734 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 result %d>", \
735 caller, (uint64_t)VM_KERNEL_ADDRPERM(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, inp ? inp->inp_policyresult.results.result : 0); \
736 }
737
738 #define NECP_DATA_TRACE_LOG_SOCKET_DP(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
739 if (NECP_DATA_TRACE_ON(debug)) { \
740 char laddr_str[MAX_IPv6_STR_LEN]; \
741 char raddr_str[MAX_IPv6_STR_LEN]; \
742 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 result %d> <input ifindex %d> <allowed_to_receive %d><pf_tag %X pass_flags %X>", \
743 caller, (uint64_t)VM_KERNEL_ADDRPERM(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, inp ? inp->inp_policyresult.results.result : 0, verifyifindex, allowed_to_receive, pf_tag, pass_flags); \
744 }
745
746 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
747 if (NECP_DATA_TRACE_ON(debug)) { \
748 char laddr_str[MAX_IPv6_STR_LEN]; \
749 char raddr_str[MAX_IPv6_STR_LEN]; \
750 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)", \
751 caller, (uint64_t)VM_KERNEL_ADDRPERM(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]); \
752 }
753
754 #define NECP_DATA_TRACE_LOG_SOCKET_BRIEF(debug, socket, caller, log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id) \
755 if (NECP_DATA_TRACE_ON(debug)) { \
756 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - <policy_id %d skip_policy_id %d> <cached policy_id %d skip_policy_id %d>", \
757 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id); \
758 }
759
760 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
761 if (NECP_DATA_TRACE_ON(debug)) { \
762 char laddr_str[MAX_IPv6_STR_LEN]; \
763 char raddr_str[MAX_IPv6_STR_LEN]; \
764 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>", \
765 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)); \
766 }
767
768 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
769 if (NECP_DATA_TRACE_ON(debug)) { \
770 char laddr_str[MAX_IPv6_STR_LEN]; \
771 char raddr_str[MAX_IPv6_STR_LEN]; \
772 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 %d>", \
773 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), packet ? packet->m_pkthdr.len : 0); \
774 }
775
776 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
777 if (NECP_DATA_TRACE_ON(debug)) { \
778 char laddr_str[MAX_IPv6_STR_LEN]; \
779 char raddr_str[MAX_IPv6_STR_LEN]; \
780 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)", \
781 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]); \
782 }
783
784 #define NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, socket, caller, log_msg) \
785 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
786 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - policy id=%d session_order=%d policy_order=%d result=%s (cond_policy_id %d) (skip_session_order %d skip_order %d)", \
787 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), 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); \
788 }
789
790 #define NECP_DATA_TRACE_LOG_POLICY_IP(debug, caller, log_msg) \
791 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
792 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)", \
793 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); \
794 }
795
796 #define NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
797 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
798 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)>", \
799 caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
800 }
801
802 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
803 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
804 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
805 caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
806 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
807 }
808
809 #define NECP_DATA_TRACE_LOG_CONDITION_IP(debug, caller, negate, name, val, input) \
810 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
811
812 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR(debug, caller, negate, name, val, input) \
813 NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
814
815
816 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
817 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
818 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value (%d / 0x%X) (%d / 0x%X) (%d / 0x%X) input (%d / 0x%X) (%d / 0x%X) (%d / 0x%X)>", \
819 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
820 }
821
822 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
823 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
824 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
825 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
826 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
827 }
828
829 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, caller, negate, name, val, input) \
830 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val, 0, 0, input, 0, 0)
831
832 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, caller, negate, name, val, input) \
833 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
834
835 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
836 (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
837 addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
838
839 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
840 "INVALID",
841 "PASS",
842 "SKIP",
843 "DROP",
844 "SOCKET_DIVERT",
845 "SOCKET_FILTER",
846 "IP_TUNNEL",
847 "IP_FILTER",
848 "TRIGGER",
849 "TRIGGER_IF_NEEDED",
850 "TRIGGER_SCOPED",
851 "NO_TRIGGER_SCOPED",
852 "SOCKET_SCOPED",
853 "ROUTE_RULES",
854 "USE_NETAGENT",
855 "NETAGENT_SCOPED",
856 "SCOPED_DIRECT",
857 "ALLOW_UNENTITLED",
858 "REMOVE_NETAGENT"
859 };
860
861
862 #define NECP_DDE_ENTITLEMENT "com.apple.developer.media-device-discovery-extension"
863
864 static int necp_drop_loopback_count = 0;
865 SYSCTL_INT(_net_necp, OID_AUTO, drop_loopback_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_drop_loopback_count, 0, "");
866
867 static bool
necp_address_is_local_interface_address(union necp_sockaddr_union * addr)868 necp_address_is_local_interface_address(union necp_sockaddr_union *addr)
869 {
870 bool is_interface_address = false;
871 if (addr == NULL) {
872 return false;
873 }
874
875 // Clean up the address before comparison with interface addresses
876 // Transform remote_addr into the ifaddr form
877 // IPv6 Scope IDs are always embedded in the ifaddr list
878 struct sockaddr_storage remote_address_sanitized;
879 u_int ifscope = IFSCOPE_NONE;
880 (void)sa_copy(SA(addr), &remote_address_sanitized, &ifscope);
881 SIN(&remote_address_sanitized)->sin_port = 0;
882 if (remote_address_sanitized.ss_family == AF_INET6) {
883 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
884 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
885 }
886 }
887
888 // Check if remote address is an interface address
889 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
890 if (ifa != NULL && ifa->ifa_ifp != NULL) {
891 is_interface_address = true;
892 }
893 if (ifa != NULL) {
894 ifaddr_release(ifa);
895 ifa = NULL;
896 }
897
898 return is_interface_address;
899 }
900
901 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, addr, include_local_addresses) \
902 ((rt) != NULL && !((rt)->rt_flags & RTF_GATEWAY) && (include_local_addresses || !((rt)->rt_flags & RTF_LOCAL)) && ((rt)->rt_ifa && (rt)->rt_ifa->ifa_ifp && !((rt)->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT) && !((rt)->rt_ifa->ifa_ifp->if_eflags & IFEF_DIRECTLINK)) && (include_local_addresses || addr == NULL || !necp_address_is_local_interface_address(addr)))
903
904 // Session order allocation
905 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)906 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
907 {
908 u_int32_t new_order = 0;
909
910 // For now, just allocate 1000 orders for each priority
911 if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
912 priority = NECP_SESSION_PRIORITY_DEFAULT;
913 }
914
915 // Use the control unit to decide the offset into the priority list
916 new_order = (control_unit) + ((priority - 1) * 1000);
917
918 return new_order;
919 }
920
921 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)922 necp_get_first_order_for_priority(u_int32_t priority)
923 {
924 if (priority == 0) {
925 return 0;
926 }
927 return ((priority - 1) * 1000) + 1;
928 }
929
930 // Sysctl handler
931 static int
932 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
933 {
934 #pragma unused(arg1, arg2)
935 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
936 necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
937 return error;
938 }
939
940 static int
941 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
942 {
943 #pragma unused(arg1, arg2)
944 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
945 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
946 return error;
947 }
948
949 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
950 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)951 _necp_process_drop_order_inner(kauth_cred_t cred)
952 {
953 if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
954 priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
955 return necp_drop_unentitled_order;
956 } else {
957 return 0;
958 }
959 }
960
961 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
962 #pragma GCC poison _necp_process_drop_order_inner
963
964 static int
965 sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS
966 {
967 #pragma unused(arg1, arg2)
968 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
969 necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
970 return error;
971 }
972
973 static inline bool
necp_socket_is_connected(struct inpcb * inp)974 necp_socket_is_connected(struct inpcb *inp)
975 {
976 return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
977 }
978
979
980 // Session fd
981
982 static int necp_session_op_close(struct fileglob *, vfs_context_t);
983
984 static const struct fileops necp_session_fd_ops = {
985 .fo_type = DTYPE_NETPOLICY,
986 .fo_read = fo_no_read,
987 .fo_write = fo_no_write,
988 .fo_ioctl = fo_no_ioctl,
989 .fo_select = fo_no_select,
990 .fo_close = necp_session_op_close,
991 .fo_drain = fo_no_drain,
992 .fo_kqfilter = fo_no_kqfilter,
993 };
994
995 static inline int
necp_is_platform_binary(proc_t proc)996 necp_is_platform_binary(proc_t proc)
997 {
998 return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
999 }
1000
1001 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)1002 necp_check_drop_all_bypass_result(proc_t proc)
1003 {
1004 if (proc == NULL) {
1005 proc = current_proc();
1006 if (proc == NULL) {
1007 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1008 }
1009 }
1010
1011 #if defined(XNU_TARGET_OS_OSX)
1012 const char *signing_id __null_terminated = NULL;
1013 const bool isConfigd = (necp_is_platform_binary(proc) &&
1014 (signing_id = cs_identity_get(proc)) &&
1015 (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
1016 (strcmp(signing_id, SIGNING_ID_CONFIGD) == 0));
1017 if (isConfigd) {
1018 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1019 }
1020 #endif
1021
1022 const task_t __single task = proc_task(proc);
1023 if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
1024 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1025 } else {
1026 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1027 }
1028 }
1029
1030 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)1031 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
1032 {
1033 #pragma unused(uap)
1034 int error = 0;
1035 struct necp_session *session = NULL;
1036 struct fileproc * __single fp = NULL;
1037 int fd = -1;
1038 uid_t uid = kauth_cred_getuid(kauth_cred_get());
1039
1040 if (!necp_is_platform_binary(p)) {
1041 NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
1042 error = EACCES;
1043 goto done;
1044 }
1045
1046 if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
1047 NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
1048 error = EACCES;
1049 goto done;
1050 }
1051
1052 error = falloc(p, &fp, &fd);
1053 if (error != 0) {
1054 goto done;
1055 }
1056
1057 session = necp_create_session();
1058 if (session == NULL) {
1059 error = ENOMEM;
1060 goto done;
1061 }
1062
1063 fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
1064 fp->fp_glob->fg_flag = 0;
1065 fp->fp_glob->fg_ops = &necp_session_fd_ops;
1066 fp_set_data(fp, session);
1067
1068 proc_fdlock(p);
1069 procfdtbl_releasefd(p, fd, NULL);
1070 fp_drop(p, fd, fp, 1);
1071 proc_fdunlock(p);
1072
1073 *retval = fd;
1074 done:
1075 if (error != 0) {
1076 if (fp != NULL) {
1077 fp_free(p, fd, fp);
1078 fp = NULL;
1079 }
1080 }
1081
1082 return error;
1083 }
1084
1085 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)1086 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
1087 {
1088 #pragma unused(ctx)
1089 struct necp_session *session = (struct necp_session *)fg_get_data(fg);
1090 fg_set_data(fg, NULL);
1091
1092 if (session != NULL) {
1093 necp_policy_mark_all_for_deletion(session);
1094 necp_policy_apply_all(session);
1095 necp_delete_session(session);
1096 return 0;
1097 } else {
1098 return ENOENT;
1099 }
1100 }
1101
1102 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)1103 necp_session_find_from_fd(struct proc *p, int fd,
1104 struct fileproc **fpp, struct necp_session **session)
1105 {
1106 struct fileproc * __single fp = NULL;
1107 int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
1108
1109 if (error == 0) {
1110 *fpp = fp;
1111 *session = (struct necp_session *)fp_get_data(fp);
1112 if ((*session)->necp_fd_type != necp_fd_type_session) {
1113 // Not a client fd, ignore
1114 fp_drop(p, fd, fp, 0);
1115 error = EINVAL;
1116 }
1117 }
1118
1119 return error;
1120 }
1121
1122 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1123 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1124 {
1125 int error = 0;
1126 u_int8_t * __indexable tlv_buffer = NULL;
1127
1128 if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
1129 NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1130 error = EINVAL;
1131 goto done;
1132 }
1133
1134 if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
1135 NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1136 error = EINVAL;
1137 goto done;
1138 }
1139
1140 if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
1141 error = ENOMEM;
1142 goto done;
1143 }
1144
1145 error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
1146 if (error != 0) {
1147 NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1148 goto done;
1149 }
1150
1151 necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1152 if (error != 0) {
1153 NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1154 goto done;
1155 }
1156
1157 error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1158 if (error != 0) {
1159 NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1160 goto done;
1161 }
1162
1163 done:
1164 if (tlv_buffer != NULL) {
1165 kfree_data(tlv_buffer, uap->in_buffer_length);
1166 tlv_buffer = NULL;
1167 }
1168 *retval = error;
1169
1170 return error;
1171 }
1172
1173 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1174 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1175 {
1176 int error = 0;
1177 u_int8_t * __indexable response = NULL;
1178
1179 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1180 NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1181 error = EINVAL;
1182 goto done;
1183 }
1184
1185 necp_policy_id policy_id = 0;
1186 error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1187 if (error != 0) {
1188 NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1189 goto done;
1190 }
1191
1192 struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1193 if (policy == NULL || policy->pending_deletion) {
1194 NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1195 error = ENOENT;
1196 goto done;
1197 }
1198
1199 u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1200 u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1201 u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1202
1203 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1204 NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1205 error = EINVAL;
1206 goto done;
1207 }
1208
1209 if (response_size > NECP_MAX_POLICY_SIZE) {
1210 NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1211 error = EINVAL;
1212 goto done;
1213 }
1214
1215 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1216 if (response == NULL) {
1217 error = ENOMEM;
1218 goto done;
1219 }
1220
1221 u_int8_t *cursor = response;
1222 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1223 if (result_tlv_size) {
1224 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, (void *)&policy->result, response, response_size);
1225 }
1226 if (policy->conditions_size) {
1227 memcpy(response + (cursor - response), policy->conditions, policy->conditions_size);
1228 }
1229
1230 error = copyout(response, uap->out_buffer, response_size);
1231 if (error != 0) {
1232 NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1233 goto done;
1234 }
1235
1236 done:
1237 if (response != NULL) {
1238 kfree_data(response, response_size);
1239 response = NULL;
1240 }
1241 *retval = error;
1242
1243 return error;
1244 }
1245
1246 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1247 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1248 {
1249 int error = 0;
1250
1251 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1252 NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1253 error = EINVAL;
1254 goto done;
1255 }
1256
1257 necp_policy_id delete_policy_id = 0;
1258 error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1259 if (error != 0) {
1260 NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1261 goto done;
1262 }
1263
1264 struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1265 if (policy == NULL || policy->pending_deletion) {
1266 NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1267 error = ENOENT;
1268 goto done;
1269 }
1270
1271 necp_policy_mark_for_deletion(session, policy);
1272 done:
1273 *retval = error;
1274 return error;
1275 }
1276
1277 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1278 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1279 {
1280 #pragma unused(uap)
1281 necp_policy_apply_all(session);
1282 *retval = 0;
1283 return 0;
1284 }
1285
1286 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1287 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1288 {
1289 u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1290 u_int32_t response_size = 0;
1291 u_int8_t * __indexable response = NULL;
1292 int num_policies = 0;
1293 int cur_policy_index = 0;
1294 int error = 0;
1295 struct necp_session_policy *policy;
1296
1297 LIST_FOREACH(policy, &session->policies, chain) {
1298 if (!policy->pending_deletion) {
1299 num_policies++;
1300 }
1301 }
1302
1303 if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1304 NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1305 error = EINVAL;
1306 goto done;
1307 }
1308
1309 response_size = num_policies * tlv_size;
1310 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1311 NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1312 error = EINVAL;
1313 goto done;
1314 }
1315
1316 // Create a response with one Policy ID TLV for each policy
1317 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1318 if (response == NULL) {
1319 error = ENOMEM;
1320 goto done;
1321 }
1322
1323 u_int8_t *cursor = response;
1324 LIST_FOREACH(policy, &session->policies, chain) {
1325 if (!policy->pending_deletion && cur_policy_index < num_policies) {
1326 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1327 cur_policy_index++;
1328 }
1329 }
1330
1331 error = copyout(response, uap->out_buffer, response_size);
1332 if (error != 0) {
1333 NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1334 goto done;
1335 }
1336
1337 done:
1338 if (response != NULL) {
1339 kfree_data(response, response_size);
1340 response = NULL;
1341 }
1342 *retval = error;
1343
1344 return error;
1345 }
1346
1347
1348 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1349 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1350 {
1351 #pragma unused(uap)
1352 necp_policy_mark_all_for_deletion(session);
1353 *retval = 0;
1354 return 0;
1355 }
1356
1357 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1358 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1359 {
1360 int error = 0;
1361 struct necp_session_policy *policy = NULL;
1362 struct necp_session_policy *temp_policy = NULL;
1363
1364 if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1365 NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1366 error = EINVAL;
1367 goto done;
1368 }
1369
1370 necp_session_priority requested_session_priority = 0;
1371 error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1372 if (error != 0) {
1373 NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1374 goto done;
1375 }
1376
1377 // Enforce special session priorities with entitlements
1378 if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1379 requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1380 requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1381 requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1382 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1383 if (cred_result != 0) {
1384 NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1385 error = EPERM;
1386 goto done;
1387 }
1388 }
1389
1390 if (session->session_priority != requested_session_priority) {
1391 session->session_priority = requested_session_priority;
1392 session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1393 session->dirty = TRUE;
1394
1395 // Mark all policies as needing updates
1396 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1397 policy->pending_update = TRUE;
1398 }
1399 }
1400
1401 done:
1402 *retval = error;
1403 return error;
1404 }
1405
1406 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1407 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1408 {
1409 #pragma unused(uap)
1410 session->proc_locked = TRUE;
1411 *retval = 0;
1412 return 0;
1413 }
1414
1415 static int
necp_session_register_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1416 necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1417 {
1418 int error = 0;
1419 struct necp_service_registration *new_service = NULL;
1420
1421 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1422 NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1423 error = EINVAL;
1424 goto done;
1425 }
1426
1427 uuid_t service_uuid;
1428 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1429 if (error != 0) {
1430 NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1431 goto done;
1432 }
1433
1434 new_service = kalloc_type(struct necp_service_registration,
1435 Z_WAITOK | Z_ZERO | Z_NOFAIL);
1436
1437 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1438 new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1439 LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1440 LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1441 lck_rw_done(&necp_kernel_policy_lock);
1442
1443 done:
1444 *retval = error;
1445 return error;
1446 }
1447
1448 static int
necp_session_unregister_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1449 necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1450 {
1451 int error = 0;
1452 struct necp_service_registration * __single service = NULL;
1453 struct necp_service_registration *temp_service = NULL;
1454 struct necp_uuid_id_mapping *mapping = NULL;
1455
1456 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1457 NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1458 error = EINVAL;
1459 goto done;
1460 }
1461
1462 uuid_t service_uuid;
1463 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1464 if (error != 0) {
1465 NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1466 goto done;
1467 }
1468
1469 // Remove all matching services for this session
1470 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1471 mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1472 if (mapping != NULL) {
1473 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1474 if (service->service_id == mapping->id) {
1475 LIST_REMOVE(service, session_chain);
1476 LIST_REMOVE(service, kernel_chain);
1477 kfree_type(struct necp_service_registration, service);
1478 }
1479 }
1480 necp_remove_uuid_service_id_mapping(service_uuid);
1481 }
1482 lck_rw_done(&necp_kernel_policy_lock);
1483
1484 done:
1485 *retval = error;
1486 return error;
1487 }
1488
1489 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1490 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1491 {
1492 #pragma unused(session)
1493 int error = 0;
1494
1495 if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1496 NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1497 error = EINVAL;
1498 goto done;
1499 }
1500
1501 error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1502 done:
1503 *retval = error;
1504 return error;
1505 }
1506
1507 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1508 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1509 {
1510 int error = 0;
1511 struct net_bloom_filter *bloom_filter = NULL;
1512 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1513 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1514
1515 if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1516 in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1517 uap->in_buffer == 0) {
1518 NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1519 error = EINVAL;
1520 goto done;
1521 }
1522
1523 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1524 NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1525 error = EINVAL;
1526 goto done;
1527 }
1528
1529 bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1530 if (bloom_filter == NULL) {
1531 NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1532 error = ENOMEM;
1533 goto done;
1534 }
1535
1536 error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1537 if (error != 0) {
1538 NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1539 goto done;
1540 }
1541
1542 size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1543 if (expected_filter_size != in_buffer_length) {
1544 NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1545 error = EINVAL;
1546 goto done;
1547 }
1548
1549 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1550 u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1551 lck_rw_done(&necp_kernel_policy_lock);
1552
1553 if (filter_id == 0) {
1554 error = ENOMEM;
1555 } else {
1556 // Bloom filter is taken over by the new filter entry, clear the local pointer
1557 bloom_filter = NULL;
1558
1559 error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1560 if (error != 0) {
1561 NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1562 goto done;
1563 }
1564 }
1565
1566 done:
1567 *retval = error;
1568 if (error != 0 && bloom_filter != NULL) {
1569 uint8_t * __single filter_buffer = (uint8_t *)bloom_filter;
1570 kfree_data(filter_buffer, in_buffer_length);
1571 bloom_filter = NULL;
1572 }
1573 return error;
1574 }
1575
1576 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1577 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1578 {
1579 int error = 0;
1580
1581 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1582 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1583 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1584 error = EINVAL;
1585 goto done;
1586 }
1587
1588 u_int32_t filter_id;
1589 error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1590 if (error != 0) {
1591 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1592 goto done;
1593 }
1594
1595 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1596 bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1597 if (!removed) {
1598 error = ENOENT;
1599 }
1600 lck_rw_done(&necp_kernel_policy_lock);
1601
1602 done:
1603 *retval = error;
1604 return error;
1605 }
1606
1607 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1608 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1609 {
1610 #pragma unused(uap)
1611
1612 struct necp_domain_filter * __single filter = NULL;
1613 struct necp_domain_filter *temp_filter = NULL;
1614 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1615 if (os_ref_release_locked(&filter->refcount) == 0) {
1616 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1617 LIST_REMOVE(filter, chain);
1618 lck_rw_done(&necp_kernel_policy_lock);
1619 LIST_REMOVE(filter, owner_chain);
1620 net_bloom_filter_destroy(filter->filter);
1621 kfree_type(struct necp_domain_filter, filter);
1622 }
1623 }
1624
1625 *retval = 0;
1626 return 0;
1627 }
1628
1629 static int
necp_session_add_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1630 necp_session_add_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1631 {
1632 int error = 0;
1633
1634 struct necp_domain_trie_request *domain_trie_request = NULL;
1635 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1636 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1637
1638 if (in_buffer_length < sizeof(struct necp_domain_trie_request) ||
1639 in_buffer_length > NECP_MAX_DOMAIN_TRIE_SIZE ||
1640 uap->in_buffer == 0) {
1641 NECPLOG(LOG_ERR, "necp_session_add_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1642 error = EINVAL;
1643 goto done;
1644 }
1645
1646 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1647 NECPLOG(LOG_ERR, "necp_session_add_domain_trie buffer not large enough (%zu)", (size_t)out_buffer_length);
1648 error = EINVAL;
1649 goto done;
1650 }
1651
1652 domain_trie_request = (struct necp_domain_trie_request *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1653 if (domain_trie_request == NULL) {
1654 NECPLOG(LOG_ERR, "necp_session_add_domain_trie allocate trie request error (%zu)", in_buffer_length);
1655 error = ENOMEM;
1656 goto done;
1657 }
1658
1659 error = copyin(uap->in_buffer, domain_trie_request, in_buffer_length);
1660 if (error != 0) {
1661 NECPLOG(LOG_ERR, "necp_session_add_domain_trie filter copyin error (%d)", error);
1662 goto done;
1663 }
1664
1665 NECPLOG(LOG_INFO, "necp_session_add_domain_trie received %zu bytes <trie mem size %d>", in_buffer_length, domain_trie_request->total_mem_size);
1666
1667 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1668 u_int32_t id = necp_create_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, domain_trie_request, in_buffer_length);
1669 lck_rw_done(&necp_kernel_policy_lock);
1670
1671 if (id == 0) {
1672 error = ENOMEM;
1673 } else {
1674 error = copyout(&id, uap->out_buffer, sizeof(id));
1675 if (error != 0) {
1676 NECPLOG(LOG_ERR, "necp_session_add_domain_trie ID copyout error (%d)", error);
1677 goto done;
1678 }
1679 }
1680
1681 done:
1682 *retval = error;
1683 if (error != 0 && domain_trie_request != NULL) {
1684 uint8_t * __single domain_buffer = (uint8_t *)domain_trie_request;
1685 kfree_data(domain_buffer, in_buffer_length);
1686 domain_trie_request = NULL;
1687 }
1688 return error;
1689 }
1690
1691 static int
necp_session_remove_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1692 necp_session_remove_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1693 {
1694 int error = 0;
1695
1696 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1697 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1698 NECPLOG(LOG_ERR, "necp_session_remove_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1699 error = EINVAL;
1700 goto done;
1701 }
1702
1703 u_int32_t id;
1704 error = copyin(uap->in_buffer, &id, sizeof(id));
1705 if (error != 0) {
1706 NECPLOG(LOG_ERR, "necp_session_remove_domain_trie uuid copyin error (%d)", error);
1707 goto done;
1708 }
1709
1710 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1711 bool removed = necp_remove_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, id);
1712 if (!removed) {
1713 error = ENOENT;
1714 }
1715 lck_rw_done(&necp_kernel_policy_lock);
1716
1717 done:
1718 *retval = error;
1719 return error;
1720 }
1721
1722 static int
necp_session_remove_all_domain_tries(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1723 necp_session_remove_all_domain_tries(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1724 {
1725 #pragma unused(uap)
1726 struct necp_domain_trie* __single trie = NULL;
1727 struct necp_domain_trie* __single temp_trie = NULL;
1728 LIST_FOREACH_SAFE(trie, &session->domain_tries, owner_chain, temp_trie) {
1729 if (os_ref_release_locked(&trie->refcount) == 0) {
1730 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1731 LIST_REMOVE(trie, chain);
1732 lck_rw_done(&necp_kernel_policy_lock);
1733 LIST_REMOVE(trie, owner_chain);
1734 necp_free_domain_trie(trie);
1735 }
1736 }
1737 *retval = 0;
1738 return 0;
1739 }
1740
1741 static int
necp_session_trie_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1742 necp_session_trie_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1743 {
1744 #pragma unused(session)
1745
1746 int error = 0;
1747
1748 uint8_t request_buffer[2000] = { 0 };
1749 uint8_t *ptr = NULL;
1750 uint32_t count = 0;
1751 int output_length = 0;
1752
1753 lck_rw_lock_shared(&necp_kernel_policy_lock);
1754 count = necp_trie_count;
1755 lck_rw_done(&necp_kernel_policy_lock);
1756
1757 if (count == 0) {
1758 error = ENOENT;
1759 goto done;
1760 }
1761
1762 output_length = sizeof(count) + (count * sizeof(struct necp_domain_trie_request)); // first byte contains count
1763 if (output_length > uap->out_buffer_length) {
1764 NECPLOG(LOG_ERR, "necp_session_trie_dump_all out_buffer not large enough for %zu", (size_t)output_length);
1765 error = EINVAL;
1766 goto done;
1767 }
1768 if (output_length > sizeof(request_buffer)) {
1769 NECPLOG(LOG_ERR, "necp_session_trie_dump_all temporary buffer not large enough for %zu", (size_t)output_length);
1770 error = EINVAL;
1771 goto done;
1772 }
1773
1774 memcpy(request_buffer, (u_int8_t *)&count, sizeof(count));
1775 ptr = request_buffer + sizeof(count);
1776
1777 lck_rw_lock_shared(&necp_kernel_policy_lock);
1778 struct necp_domain_trie* __single trie = NULL;
1779 LIST_FOREACH(trie, &necp_global_domain_trie_list, chain) {
1780 if (trie->trie_request != NULL) {
1781 memcpy((u_int8_t *)ptr, (u_int8_t *)trie->trie_request, sizeof(struct necp_domain_trie_request));
1782 ptr += sizeof(struct necp_domain_trie_request);
1783 }
1784 }
1785 lck_rw_done(&necp_kernel_policy_lock);
1786
1787 error = copyout(request_buffer, uap->out_buffer, output_length);
1788
1789 done:
1790 *retval = error;
1791 return error;
1792 }
1793
1794 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1795 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1796 {
1797 struct fileproc * __single fp;
1798 int error = 0;
1799 int return_value = 0;
1800 struct necp_session * __single session = NULL;
1801
1802 error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1803 if (error != 0) {
1804 NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1805 return error;
1806 }
1807
1808 NECP_SESSION_LOCK(session);
1809
1810 if (session->proc_locked) {
1811 // Verify that the calling process is allowed to do actions
1812 uuid_t proc_uuid;
1813 proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1814 if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1815 error = EPERM;
1816 goto done;
1817 }
1818 } else {
1819 // If not locked, update the proc_uuid and proc_pid of the session
1820 proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1821 session->proc_pid = proc_pid(current_proc());
1822 }
1823
1824 u_int32_t action = uap->action;
1825 switch (action) {
1826 case NECP_SESSION_ACTION_POLICY_ADD: {
1827 return_value = necp_session_add_policy(session, uap, retval);
1828 break;
1829 }
1830 case NECP_SESSION_ACTION_POLICY_GET: {
1831 return_value = necp_session_get_policy(session, uap, retval);
1832 break;
1833 }
1834 case NECP_SESSION_ACTION_POLICY_DELETE: {
1835 return_value = necp_session_delete_policy(session, uap, retval);
1836 break;
1837 }
1838 case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1839 return_value = necp_session_apply_all(session, uap, retval);
1840 break;
1841 }
1842 case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1843 return_value = necp_session_list_all(session, uap, retval);
1844 break;
1845 }
1846 case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1847 return_value = necp_session_delete_all(session, uap, retval);
1848 break;
1849 }
1850 case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1851 return_value = necp_session_set_session_priority(session, uap, retval);
1852 break;
1853 }
1854 case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1855 return_value = necp_session_lock_to_process(session, uap, retval);
1856 break;
1857 }
1858 case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1859 return_value = necp_session_register_service(session, uap, retval);
1860 break;
1861 }
1862 case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1863 return_value = necp_session_unregister_service(session, uap, retval);
1864 break;
1865 }
1866 case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1867 return_value = necp_session_dump_all(session, uap, retval);
1868 break;
1869 }
1870 case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1871 return_value = necp_session_add_domain_filter(session, uap, retval);
1872 break;
1873 }
1874 case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1875 return_value = necp_session_remove_domain_filter(session, uap, retval);
1876 break;
1877 }
1878 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1879 return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1880 break;
1881 }
1882 case NECP_SESSION_ACTION_ADD_DOMAIN_TRIE: {
1883 return_value = necp_session_add_domain_trie(session, uap, retval);
1884 break;
1885 }
1886 case NECP_SESSION_ACTION_REMOVE_DOMAIN_TRIE: {
1887 return_value = necp_session_remove_domain_trie(session, uap, retval);
1888 break;
1889 }
1890 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_TRIES: {
1891 return_value = necp_session_remove_all_domain_tries(session, uap, retval);
1892 break;
1893 }
1894 case NECP_SESSION_ACTION_TRIE_DUMP_ALL: {
1895 return_value = necp_session_trie_dump_all(session, uap, retval);
1896 break;
1897 }
1898 default: {
1899 NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1900 return_value = EINVAL;
1901 break;
1902 }
1903 }
1904
1905 done:
1906 NECP_SESSION_UNLOCK(session);
1907 fp_drop(p, uap->necp_fd, fp, 0);
1908 return return_value;
1909 }
1910
1911 struct necp_resolver_key_state {
1912 const struct ccdigest_info *digest_info;
1913 uint8_t key[CCSHA256_OUTPUT_SIZE];
1914 };
1915 static struct necp_resolver_key_state s_necp_resolver_key_state;
1916
1917 static void
necp_generate_resolver_key(void)1918 necp_generate_resolver_key(void)
1919 {
1920 s_necp_resolver_key_state.digest_info = ccsha256_di();
1921 cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1922 }
1923
1924 static void
necp_sign_update_context(const struct ccdigest_info * di,cchmac_ctx_t ctx,uuid_t client_id,u_int32_t sign_type,u_int8_t * data,size_t data_length)1925 necp_sign_update_context(const struct ccdigest_info *di,
1926 cchmac_ctx_t ctx,
1927 uuid_t client_id,
1928 u_int32_t sign_type,
1929 u_int8_t *data,
1930 size_t data_length)
1931 {
1932 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1933 const char * __null_terminated context_string = "NECP Resolver Binder";
1934 uint8_t separator = 0;
1935 cchmac_update(di, ctx, sizeof(context), context);
1936 cchmac_update(di, ctx, strlen(context_string), __unsafe_null_terminated_to_indexable(context_string));
1937 cchmac_update(di, ctx, sizeof(separator), &separator);
1938 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1939 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1940 cchmac_update(di, ctx, data_length, data);
1941 }
1942
1943 int
necp_sign_resolver_answer(uuid_t client_id,u_int32_t sign_type,u_int8_t * data,size_t data_length,u_int8_t * tag,size_t * out_tag_length)1944 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1945 u_int8_t *data, size_t data_length,
1946 u_int8_t *tag, size_t *out_tag_length)
1947 {
1948 if (s_necp_resolver_key_state.digest_info == NULL) {
1949 return EINVAL;
1950 }
1951
1952 if (data == NULL ||
1953 data_length == 0 ||
1954 tag == NULL ||
1955 out_tag_length == NULL) {
1956 return EINVAL;
1957 }
1958
1959 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1960 if (*out_tag_length < required_tag_length) {
1961 return ERANGE;
1962 }
1963
1964 *out_tag_length = required_tag_length;
1965
1966 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1967 s_necp_resolver_key_state.digest_info->block_size, ctx);
1968 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1969 sizeof(s_necp_resolver_key_state.key),
1970 s_necp_resolver_key_state.key);
1971 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1972 ctx, client_id, sign_type, data, data_length);
1973 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1974
1975 return 0;
1976 }
1977
1978 bool
necp_validate_resolver_answer(uuid_t client_id,u_int32_t sign_type,u_int8_t * __sized_by (data_length)data,size_t data_length,u_int8_t * __sized_by (tag_length)tag,size_t tag_length)1979 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1980 u_int8_t * __sized_by(data_length)data, size_t data_length,
1981 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1982 {
1983 if (s_necp_resolver_key_state.digest_info == NULL) {
1984 return false;
1985 }
1986
1987 if (data == NULL ||
1988 data_length == 0 ||
1989 tag == NULL ||
1990 tag_length == 0) {
1991 return false;
1992 }
1993
1994 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1995 if (tag_length != required_tag_length) {
1996 return false;
1997 }
1998
1999 uint8_t actual_tag[required_tag_length];
2000
2001 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
2002 s_necp_resolver_key_state.digest_info->block_size, ctx);
2003 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
2004 sizeof(s_necp_resolver_key_state.key),
2005 s_necp_resolver_key_state.key);
2006 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
2007 ctx, client_id, sign_type, data, data_length);
2008 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
2009
2010 return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
2011 }
2012
2013 struct necp_application_id_key_state {
2014 const struct ccdigest_info *digest_info;
2015 uint8_t key[CCSHA256_OUTPUT_SIZE];
2016 };
2017 static struct necp_application_id_key_state s_necp_application_id_key_state;
2018
2019 static void
necp_generate_application_id_key(void)2020 necp_generate_application_id_key(void)
2021 {
2022 s_necp_application_id_key_state.digest_info = ccsha256_di();
2023 cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
2024 }
2025
2026 static void
necp_sign_application_id_update_context(const struct ccdigest_info * di,cchmac_ctx_t ctx,uuid_t client_id,u_int32_t sign_type)2027 necp_sign_application_id_update_context(const struct ccdigest_info *di,
2028 cchmac_ctx_t ctx,
2029 uuid_t client_id,
2030 u_int32_t sign_type)
2031 {
2032 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
2033 const char context_string[] = "NECP Application ID";
2034 uint8_t separator = 0;
2035 cchmac_update(di, ctx, sizeof(context), context);
2036 cchmac_update(di, ctx, sizeof(context_string) - 1, context_string);
2037 cchmac_update(di, ctx, sizeof(separator), &separator);
2038 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
2039 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
2040 }
2041
2042 int
necp_sign_application_id(uuid_t client_id,u_int32_t sign_type,u_int8_t * __counted_by (* out_tag_length)tag,size_t * out_tag_length)2043 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
2044 u_int8_t *__counted_by(*out_tag_length)tag, size_t *out_tag_length)
2045 {
2046 if (s_necp_application_id_key_state.digest_info == NULL) {
2047 return EINVAL;
2048 }
2049
2050 if (tag == NULL ||
2051 out_tag_length == NULL) {
2052 return EINVAL;
2053 }
2054
2055 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2056 if (*out_tag_length < required_tag_length) {
2057 return ERANGE;
2058 }
2059
2060 *out_tag_length = required_tag_length;
2061
2062 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2063 s_necp_application_id_key_state.digest_info->block_size, ctx);
2064 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2065 sizeof(s_necp_application_id_key_state.key),
2066 s_necp_application_id_key_state.key);
2067 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2068 ctx, client_id, sign_type);
2069 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
2070
2071 return 0;
2072 }
2073
2074 bool
necp_validate_application_id(uuid_t client_id,u_int32_t sign_type,u_int8_t * __sized_by (tag_length)tag,size_t tag_length)2075 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
2076 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
2077 {
2078 if (s_necp_application_id_key_state.digest_info == NULL) {
2079 return false;
2080 }
2081
2082 if (tag == NULL ||
2083 tag_length == 0) {
2084 return false;
2085 }
2086
2087 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2088 if (tag_length != required_tag_length) {
2089 return false;
2090 }
2091
2092 uint8_t actual_tag[required_tag_length];
2093
2094 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2095 s_necp_application_id_key_state.digest_info->block_size, ctx);
2096 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2097 sizeof(s_necp_application_id_key_state.key),
2098 s_necp_application_id_key_state.key);
2099 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2100 ctx, client_id, sign_type);
2101 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
2102
2103 return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
2104 }
2105
2106 void
necp_init(void)2107 necp_init(void)
2108 {
2109 necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
2110 necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
2111
2112 necp_client_init();
2113
2114 TAILQ_INIT(&necp_session_list);
2115
2116 LIST_INIT(&necp_kernel_socket_policies);
2117 LIST_INIT(&necp_kernel_ip_output_policies);
2118
2119 LIST_INIT(&necp_account_id_list);
2120
2121 LIST_INIT(&necp_uuid_service_id_list);
2122
2123 LIST_INIT(&necp_registered_service_list);
2124
2125 LIST_INIT(&necp_route_rules);
2126 LIST_INIT(&necp_aggregate_route_rules);
2127
2128 LIST_INIT(&necp_global_domain_filter_list);
2129 LIST_INIT(&necp_global_domain_trie_list);
2130
2131 necp_generate_resolver_key();
2132 necp_generate_application_id_key();
2133
2134 necp_uuid_app_id_hashtbl = __unsafe_forge_bidi_indexable(struct necp_uuid_id_mapping_head *,
2135 hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask),
2136 NECP_UUID_APP_ID_HASH_SIZE * sizeof(void*));
2137 necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
2138 necp_num_uuid_app_id_mappings = 0;
2139 necp_uuid_app_id_mappings_dirty = FALSE;
2140
2141 necp_kernel_application_policies_condition_mask = 0;
2142 necp_kernel_socket_policies_condition_mask = 0;
2143 necp_kernel_ip_output_policies_condition_mask = 0;
2144
2145 necp_kernel_application_policies_count = 0;
2146 necp_kernel_socket_policies_count = 0;
2147 necp_kernel_socket_policies_non_app_count = 0;
2148 necp_kernel_ip_output_policies_count = 0;
2149 necp_kernel_ip_output_policies_non_id_count = 0;
2150
2151 necp_kernel_socket_policies_gencount = 1;
2152
2153 memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
2154 memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
2155 necp_kernel_socket_policies_app_layer_map = NULL;
2156
2157 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
2158 necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
2159 }
2160
2161 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)2162 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
2163 {
2164 struct kev_msg ev_msg;
2165 memset(&ev_msg, 0, sizeof(ev_msg));
2166
2167 ev_msg.vendor_code = KEV_VENDOR_APPLE;
2168 ev_msg.kev_class = KEV_NETWORK_CLASS;
2169 ev_msg.kev_subclass = KEV_NECP_SUBCLASS;
2170 ev_msg.event_code = KEV_NECP_POLICIES_CHANGED;
2171
2172 ev_msg.dv[0].data_ptr = necp_event_data;
2173 ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
2174 ev_msg.dv[1].data_length = 0;
2175
2176 kev_post_msg(&ev_msg);
2177 }
2178
2179 static inline bool
necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor,u_int8_t type,u_int32_t length,u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length)2180 necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor, u_int8_t type, u_int32_t length,
2181 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2182 {
2183 if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
2184 NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
2185 return false;
2186 }
2187 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2188 if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
2189 (uintptr_t)(next_tlv - buffer) > buffer_length) { // make sure the next TLV has enough room in buffer
2190 NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
2191 length, buffer_length);
2192 return false;
2193 }
2194 return true;
2195 }
2196
2197 u_int8_t * __counted_by(0)
2198 necp_buffer_write_tlv_if_different(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2199 u_int32_t length, const void * __sized_by(length)value, bool *updated,
2200 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2201 {
2202 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2203 u_int8_t * cursor = buffer + (cursor_ - buffer);
2204 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2205 // If we can't fit this TLV, return the current cursor
2206 return cursor;
2207 }
2208 u_int8_t * __indexable next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2209 if (*updated || *(u_int8_t *)(cursor) != type) {
2210 *(u_int8_t *)(cursor) = type;
2211 *updated = TRUE;
2212 }
2213 if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
2214 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2215 *updated = TRUE;
2216 }
2217 if (length > 0) {
2218 if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
2219 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2220 *updated = TRUE;
2221 }
2222 }
2223 return next_tlv;
2224 }
2225
2226 u_int8_t * __counted_by(0)
2227 necp_buffer_write_tlv(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2228 u_int32_t length, const void * __sized_by(length)value,
2229 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2230 {
2231 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2232 u_int8_t * cursor = buffer + (cursor_ - buffer);
2233 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2234 return NULL;
2235 }
2236 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2237 *(u_int8_t *)(cursor) = type;
2238 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2239 if (length > 0) {
2240 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2241 }
2242
2243 return next_tlv;
2244 }
2245
2246 static u_int8_t * __counted_by(0)
2247 necp_buffer_write_tlv_with_flags(u_int8_t * __counted_by(0)cursor_, u_int8_t type, u_int8_t flags,
2248 u_int32_t length, const void * __sized_by(length)value,
2249 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2250 {
2251 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2252 // Add one extra byte to 'length' to account for the flags byte for validation.
2253 u_int8_t * cursor = buffer + (cursor_ - buffer);
2254 if (!necp_buffer_write_tlv_validate(cursor, type, length + 1, buffer, buffer_length)) {
2255 return NULL;
2256 }
2257 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(flags) + sizeof(length) + length);
2258
2259 // TLV with flags format: type, length, flags, value (added 1 byte for the leading flags)
2260 *(u_int8_t *)(cursor) = type;
2261 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2262 *(u_int8_t *)(cursor + sizeof(type) + sizeof(length)) = flags;
2263 if (length > 0) {
2264 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length) + sizeof(flags)), value, length);
2265 }
2266
2267 return next_tlv;
2268 }
2269
2270 u_int8_t
necp_buffer_get_tlv_type(u_int8_t * __counted_by (buffer_length)buffer,size_t buffer_length,u_int32_t tlv_offset)2271 necp_buffer_get_tlv_type(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2272 {
2273 u_int8_t * __indexable type = NULL;
2274 uint64_t end_offset = 0;
2275
2276 if (buffer == NULL ||
2277 os_add_overflow(tlv_offset, sizeof(u_int8_t), &end_offset) || buffer_length < end_offset) {
2278 return 0;
2279 }
2280
2281 type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
2282 return type ? *type : 0;
2283 }
2284
2285 u_int32_t
necp_buffer_get_tlv_length(u_int8_t * __counted_by (buffer_length)buffer,size_t buffer_length,u_int32_t tlv_offset)2286 necp_buffer_get_tlv_length(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2287 {
2288 u_int32_t * __indexable length = NULL;
2289 uint64_t end_offset = 0;
2290
2291 if (buffer == NULL ||
2292 os_add_overflow(tlv_offset, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2293 return 0;
2294 }
2295
2296 length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
2297 return length ? *length : 0;
2298 }
2299
2300 u_int8_t *__sized_by(*value_size)
__necp_buffer_get_tlv_value(u_int8_t * __counted_by (buffer_length)buffer,size_t buffer_length,u_int32_t tlv_offset,u_int32_t * value_size)2301 __necp_buffer_get_tlv_value(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset, u_int32_t * value_size)
2302 {
2303 u_int8_t * __indexable value = NULL;
2304 uint64_t end_offset = 0;
2305
2306 if (buffer == NULL) {
2307 return NULL;
2308 }
2309
2310 u_int32_t length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2311 if (length == 0) {
2312 return NULL;
2313 }
2314
2315 if (os_add3_overflow(tlv_offset, length, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2316 return NULL;
2317 }
2318
2319 if (value_size) {
2320 *value_size = length;
2321 }
2322
2323 value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2324 return value;
2325 }
2326
2327 int
necp_buffer_find_tlv(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)2328 necp_buffer_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2329 {
2330 if (err != NULL) {
2331 *err = ENOENT;
2332 }
2333 if (offset < 0) {
2334 if (err != NULL) {
2335 *err = EINVAL;
2336 }
2337 return -1;
2338 }
2339 int cursor = offset;
2340 int next_cursor;
2341 u_int32_t curr_length;
2342 u_int8_t curr_type;
2343
2344 while (TRUE) {
2345 if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
2346 return -1;
2347 }
2348 if (!next) {
2349 curr_type = necp_buffer_get_tlv_type(buffer, buffer_length, cursor);
2350 } else {
2351 next = 0;
2352 curr_type = NECP_TLV_NIL;
2353 }
2354 curr_length = necp_buffer_get_tlv_length(buffer, buffer_length, cursor);
2355 if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
2356 return -1;
2357 }
2358
2359 next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
2360 if (curr_type == type) {
2361 // check if entire TLV fits inside buffer
2362 if (((u_int32_t)next_cursor) <= buffer_length) {
2363 if (err != NULL) {
2364 *err = 0;
2365 }
2366 return cursor;
2367 } else {
2368 return -1;
2369 }
2370 }
2371 cursor = next_cursor;
2372 }
2373 }
2374
2375 static int
necp_find_tlv(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)2376 necp_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2377 {
2378 int cursor = -1;
2379 if (buffer != NULL) {
2380 cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2381 }
2382 return cursor;
2383 }
2384
2385 static int
necp_get_tlv_at_offset(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int tlv_offset,u_int32_t out_buffer_length,void * __indexable out_buffer,u_int32_t * value_size)2386 necp_get_tlv_at_offset(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2387 int tlv_offset, u_int32_t out_buffer_length, void * __indexable out_buffer, u_int32_t *value_size)
2388 {
2389 if (buffer == NULL) {
2390 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2391 return EINVAL;
2392 }
2393
2394 // Handle buffer parsing
2395
2396 // Validate that buffer has enough room for any TLV
2397 if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2398 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2399 buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2400 return EINVAL;
2401 }
2402
2403 // Validate that buffer has enough room for this TLV
2404 u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2405 if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2406 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2407 tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2408 return EINVAL;
2409 }
2410
2411 if (out_buffer != NULL && out_buffer_length > 0) {
2412 // Validate that out buffer is large enough for value
2413 if (out_buffer_length < tlv_length) {
2414 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2415 out_buffer_length, tlv_length);
2416 return EINVAL;
2417 }
2418
2419 // Get value pointer
2420 u_int8_t * __indexable tlv_value = necp_buffer_get_tlv_value(buffer, buffer_length, tlv_offset, NULL);
2421 if (tlv_value == NULL) {
2422 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2423 return ENOENT;
2424 }
2425
2426 // Copy value
2427 memcpy(out_buffer, tlv_value, tlv_length);
2428 }
2429
2430 // Copy out length
2431 if (value_size != NULL) {
2432 *value_size = tlv_length;
2433 }
2434
2435 return 0;
2436 }
2437
2438 static int
necp_get_tlv(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int offset,u_int8_t type,u_int32_t buff_len,void * __indexable buff,u_int32_t * value_size)2439 necp_get_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2440 int offset, u_int8_t type, u_int32_t buff_len, void * __indexable buff, u_int32_t *value_size)
2441 {
2442 int error = 0;
2443
2444 int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2445 if (tlv_offset < 0) {
2446 return error;
2447 }
2448
2449 return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2450 }
2451
2452 // Session Management
2453
2454 static struct necp_session *
necp_create_session(void)2455 necp_create_session(void)
2456 {
2457 struct necp_session *new_session = NULL;
2458
2459 new_session = kalloc_type(struct necp_session,
2460 Z_WAITOK | Z_ZERO | Z_NOFAIL);
2461
2462 new_session->necp_fd_type = necp_fd_type_session;
2463 new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2464 new_session->dirty = FALSE;
2465 LIST_INIT(&new_session->policies);
2466 LIST_INIT(&new_session->services);
2467 LIST_INIT(&new_session->domain_filters);
2468 LIST_INIT(&new_session->domain_tries);
2469 lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2470
2471 // Take the lock
2472 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2473
2474 // Find the next available control unit
2475 u_int32_t control_unit = 1;
2476 struct necp_session *next_session = NULL;
2477 TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2478 if (next_session->control_unit > control_unit) {
2479 // Found a gap, grab this control unit
2480 break;
2481 }
2482
2483 // Try the next control unit, loop around
2484 control_unit = next_session->control_unit + 1;
2485 }
2486
2487 new_session->control_unit = control_unit;
2488 new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2489
2490 if (next_session != NULL) {
2491 TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2492 } else {
2493 TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2494 }
2495
2496 necp_session_count++;
2497 lck_rw_done(&necp_kernel_policy_lock);
2498
2499 if (necp_debug) {
2500 NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2501 }
2502
2503 return new_session;
2504 }
2505
2506 static void
necp_delete_session(struct necp_session * session)2507 necp_delete_session(struct necp_session *session)
2508 {
2509 if (session != NULL) {
2510 struct necp_service_registration * __single service = NULL;
2511 struct necp_service_registration *temp_service = NULL;
2512 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
2513 LIST_REMOVE(service, session_chain);
2514 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2515 LIST_REMOVE(service, kernel_chain);
2516 lck_rw_done(&necp_kernel_policy_lock);
2517 kfree_type(struct necp_service_registration, service);
2518 }
2519 struct necp_domain_filter * __single filter = NULL;
2520 struct necp_domain_filter *temp_filter = NULL;
2521 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2522 if (os_ref_release_locked(&filter->refcount) == 0) {
2523 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2524 LIST_REMOVE(filter, chain);
2525 lck_rw_done(&necp_kernel_policy_lock);
2526 LIST_REMOVE(filter, owner_chain);
2527 net_bloom_filter_destroy(filter->filter);
2528 kfree_type(struct necp_domain_filter, filter);
2529 }
2530 }
2531 if (necp_debug) {
2532 NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2533 }
2534
2535 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2536 TAILQ_REMOVE(&necp_session_list, session, chain);
2537 necp_session_count--;
2538 lck_rw_done(&necp_kernel_policy_lock);
2539
2540 lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2541 kfree_type(struct necp_session, session);
2542 }
2543 }
2544
2545 // Session Policy Management
2546
2547 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2548 necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2549 {
2550 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2551 }
2552
2553 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2554 necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2555 {
2556 return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2557 }
2558
2559 static inline u_int8_t * __indexable
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2560 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2561 {
2562 return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2563 }
2564
2565 static bool
necp_policy_result_requires_route_rules(u_int8_t * __sized_by (length)buffer,u_int32_t length)2566 necp_policy_result_requires_route_rules(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2567 {
2568 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2569 if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2570 return TRUE;
2571 }
2572 return FALSE;
2573 }
2574
2575 static inline bool
_necp_address_is_valid(struct sockaddr * address)2576 _necp_address_is_valid(struct sockaddr *address)
2577 {
2578 if (address->sa_family == AF_INET) {
2579 return address->sa_len == sizeof(struct sockaddr_in);
2580 } else if (address->sa_family == AF_INET6) {
2581 return address->sa_len == sizeof(struct sockaddr_in6);
2582 } else {
2583 return FALSE;
2584 }
2585 }
2586
2587 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2588
2589 static bool
necp_policy_result_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,bool * is_pass_skip)2590 necp_policy_result_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, bool *is_pass_skip)
2591 {
2592 bool validated = FALSE;
2593 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2594 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2595 *is_pass_skip = FALSE;
2596 switch (type) {
2597 case NECP_POLICY_RESULT_PASS: {
2598 *is_pass_skip = TRUE;
2599 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2600 validated = TRUE;
2601 }
2602 break;
2603 }
2604 case NECP_POLICY_RESULT_DROP: {
2605 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2606 validated = TRUE;
2607 }
2608 break;
2609 }
2610 case NECP_POLICY_RESULT_ROUTE_RULES:
2611 case NECP_POLICY_RESULT_SCOPED_DIRECT:
2612 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2613 validated = TRUE;
2614 break;
2615 }
2616 case NECP_POLICY_RESULT_SKIP:
2617 *is_pass_skip = TRUE;
2618 case NECP_POLICY_RESULT_SOCKET_DIVERT:
2619 case NECP_POLICY_RESULT_SOCKET_FILTER: {
2620 if (parameter_length >= sizeof(u_int32_t)) {
2621 validated = TRUE;
2622 }
2623 break;
2624 }
2625 case NECP_POLICY_RESULT_IP_TUNNEL: {
2626 if (parameter_length > sizeof(u_int32_t)) {
2627 validated = TRUE;
2628 }
2629 break;
2630 }
2631 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2632 if (parameter_length > 0) {
2633 validated = TRUE;
2634 }
2635 break;
2636 }
2637 case NECP_POLICY_RESULT_USE_NETAGENT:
2638 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2639 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2640 if (parameter_length >= sizeof(uuid_t)) {
2641 validated = TRUE;
2642 }
2643 break;
2644 }
2645 default: {
2646 validated = FALSE;
2647 break;
2648 }
2649 }
2650
2651 if (necp_debug) {
2652 NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2653 }
2654
2655 return validated;
2656 }
2657
2658 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2659 necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2660 {
2661 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2662 }
2663
2664 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2665 necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2666 {
2667 return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2668 }
2669
2670 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2671 necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2672 {
2673 return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2674 }
2675
2676 static inline u_int8_t * __indexable
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2677 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2678 {
2679 return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2680 }
2681
2682 static inline bool
necp_policy_condition_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2683 necp_policy_condition_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2684 {
2685 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2686 }
2687
2688 static inline bool
necp_policy_condition_is_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2689 necp_policy_condition_is_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2690 {
2691 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2692 }
2693
2694 static inline bool
necp_policy_condition_is_real_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2695 necp_policy_condition_is_real_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2696 {
2697 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2698 }
2699
2700 static inline bool
necp_policy_condition_requires_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2701 necp_policy_condition_requires_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2702 {
2703 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2704 return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2705 }
2706
2707 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2708 necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2709 {
2710 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2711 u_int32_t condition_length = 0;
2712 pid_t *condition_value = NULL;
2713
2714 if (type == NECP_POLICY_CONDITION_PID) {
2715 condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2716 if (condition_length >= sizeof(pid_t)) {
2717 condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2718 return *condition_value == 0;
2719 }
2720 }
2721 return false;
2722 }
2723
2724 static bool
necp_policy_condition_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,u_int8_t policy_result_type)2725 necp_policy_condition_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, u_int8_t policy_result_type)
2726 {
2727 bool validated = FALSE;
2728 bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2729 policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2730 policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2731 policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2732 policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2733 policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2734 policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2735 policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2736 policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2737 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2738 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2739 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2740 u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2741 switch (type) {
2742 case NECP_POLICY_CONDITION_APPLICATION:
2743 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2744 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2745 condition_length >= sizeof(uuid_t) &&
2746 condition_value != NULL &&
2747 !uuid_is_null(condition_value)) {
2748 validated = TRUE;
2749 }
2750 break;
2751 }
2752 case NECP_POLICY_CONDITION_DOMAIN:
2753 case NECP_POLICY_CONDITION_ACCOUNT:
2754 case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2755 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2756 case NECP_POLICY_CONDITION_URL: {
2757 if (condition_length > 0) {
2758 validated = TRUE;
2759 }
2760 break;
2761 }
2762 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2763 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2764 validated = TRUE;
2765 }
2766 break;
2767 }
2768 case NECP_POLICY_CONDITION_DEFAULT:
2769 case NECP_POLICY_CONDITION_ALL_INTERFACES:
2770 case NECP_POLICY_CONDITION_ENTITLEMENT:
2771 case NECP_POLICY_CONDITION_HAS_CLIENT:
2772 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
2773 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2774 validated = TRUE;
2775 }
2776 break;
2777 }
2778 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2779 if (condition_length == 0 || condition_length >= sizeof(u_int8_t)) {
2780 validated = TRUE;
2781 }
2782 break;
2783 }
2784 case NECP_POLICY_CONDITION_SDK_VERSION: {
2785 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2786 condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2787 validated = TRUE;
2788 }
2789 break;
2790 }
2791 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2792 if (condition_length >= sizeof(u_int16_t)) {
2793 validated = TRUE;
2794 }
2795 break;
2796 }
2797 case NECP_POLICY_CONDITION_PID: {
2798 if (condition_length >= sizeof(pid_t) &&
2799 condition_value != NULL) {
2800 validated = TRUE;
2801 }
2802 break;
2803 }
2804 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2805 if (condition_length >= sizeof(u_int32_t)) {
2806 validated = TRUE;
2807 }
2808 break;
2809 }
2810 case NECP_POLICY_CONDITION_UID:
2811 case NECP_POLICY_CONDITION_REAL_UID: {
2812 if (condition_length >= sizeof(uid_t)) {
2813 validated = TRUE;
2814 }
2815 break;
2816 }
2817 case NECP_POLICY_CONDITION_LOCAL_ADDR:
2818 case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2819 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2820 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2821 validated = TRUE;
2822 }
2823 break;
2824 }
2825 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2826 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2827 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2828 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2829 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2830 validated = TRUE;
2831 }
2832 break;
2833 }
2834 case NECP_POLICY_CONDITION_AGENT_TYPE: {
2835 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2836 condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2837 validated = TRUE;
2838 }
2839 break;
2840 }
2841 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2842 if (condition_length >= sizeof(u_int16_t)) {
2843 validated = TRUE;
2844 }
2845 break;
2846 }
2847 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2848 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2849 if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2850 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2851 validated = TRUE;
2852 }
2853 break;
2854 }
2855 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2856 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2857 if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2858 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2859 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2860 validated = TRUE;
2861 }
2862 break;
2863 }
2864 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2865 if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2866 validated = TRUE;
2867 }
2868 break;
2869 }
2870 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2871 validated = TRUE;
2872 break;
2873 }
2874 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2875 validated = TRUE;
2876 break;
2877 }
2878 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2879 if (condition_length >= sizeof(u_int16_t)) {
2880 u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2881 if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2882 validated = TRUE;
2883 }
2884 }
2885 break;
2886 }
2887 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2888 validated = TRUE;
2889 break;
2890 }
2891 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
2892 validated = TRUE;
2893 break;
2894 }
2895 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2896 validated = TRUE;
2897 break;
2898 }
2899 case NECP_POLICY_CONDITION_SCHEME_PORT: {
2900 if (condition_length >= sizeof(u_int16_t)) {
2901 validated = TRUE;
2902 }
2903 break;
2904 }
2905 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2906 if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2907 validated = TRUE;
2908 }
2909 break;
2910 }
2911 default: {
2912 validated = FALSE;
2913 break;
2914 }
2915 }
2916
2917 if (necp_debug) {
2918 NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2919 }
2920
2921 return validated;
2922 }
2923
2924 static bool
necp_policy_route_rule_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2925 necp_policy_route_rule_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2926 {
2927 return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2928 necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2929 }
2930
2931 static bool
necp_policy_route_rule_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2932 necp_policy_route_rule_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2933 {
2934 bool validated = FALSE;
2935 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2936 switch (type) {
2937 case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2938 validated = TRUE;
2939 break;
2940 }
2941 case NECP_ROUTE_RULE_DENY_INTERFACE: {
2942 validated = TRUE;
2943 break;
2944 }
2945 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2946 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2947 validated = (rule_length >= sizeof(u_int32_t));
2948 break;
2949 }
2950 case NECP_ROUTE_RULE_QOS_MARKING: {
2951 validated = TRUE;
2952 break;
2953 }
2954 case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2955 validated = TRUE;
2956 break;
2957 }
2958 case NECP_ROUTE_RULE_USE_NETAGENT:
2959 case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2960 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2961 validated = (rule_length >= sizeof(uuid_t));
2962 break;
2963 }
2964 case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2965 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2966 validated = (rule_length >= sizeof(uint32_t));
2967 break;
2968 }
2969 default: {
2970 validated = FALSE;
2971 break;
2972 }
2973 }
2974
2975 if (necp_debug) {
2976 NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2977 }
2978
2979 return validated;
2980 }
2981
2982 static int
necp_get_posix_error_for_necp_error(int response_error)2983 necp_get_posix_error_for_necp_error(int response_error)
2984 {
2985 switch (response_error) {
2986 case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2987 case NECP_ERROR_INVALID_TLV:
2988 case NECP_ERROR_POLICY_RESULT_INVALID:
2989 case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2990 case NECP_ERROR_ROUTE_RULES_INVALID: {
2991 return EINVAL;
2992 }
2993 case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2994 return ENOENT;
2995 }
2996 case NECP_ERROR_INVALID_PROCESS: {
2997 return EPERM;
2998 }
2999 case NECP_ERROR_INTERNAL:
3000 default: {
3001 return ENOMEM;
3002 }
3003 }
3004 }
3005
3006 static necp_policy_id
necp_handle_policy_add(struct necp_session * session,u_int8_t * __sized_by (tlv_buffer_length)tlv_buffer,size_t tlv_buffer_length,int offset,int * return_error)3007 necp_handle_policy_add(struct necp_session *session,
3008 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
3009 {
3010 bool has_default_condition = FALSE;
3011 bool has_non_default_condition = FALSE;
3012 bool has_application_condition = FALSE;
3013 bool has_real_application_condition = FALSE;
3014 bool requires_application_condition = FALSE;
3015 bool has_kernel_pid = FALSE;
3016 bool is_pass_skip = FALSE;
3017 u_int32_t conditions_array_size = 0;
3018 u_int8_t *conditions_array = NULL;
3019 int conditions_array_cursor;
3020
3021 bool has_default_route_rule = FALSE;
3022 u_int32_t route_rules_array_size = 0;
3023 u_int8_t *route_rules_array = NULL;
3024 int route_rules_array_cursor;
3025
3026 int cursor;
3027 int error = 0;
3028 u_int32_t response_error = NECP_ERROR_INTERNAL;
3029
3030 necp_policy_order order = 0;
3031 struct necp_session_policy *policy = NULL;
3032 u_int32_t policy_result_size = 0;
3033 u_int8_t *policy_result = NULL;
3034
3035 // Read policy order
3036 error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
3037 if (error) {
3038 NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
3039 response_error = NECP_ERROR_INVALID_TLV;
3040 goto fail;
3041 }
3042
3043 // Read policy result
3044 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
3045 if (error || cursor < 0) {
3046 NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
3047 response_error = NECP_ERROR_INVALID_TLV;
3048 goto fail;
3049 }
3050
3051 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
3052 if (error || policy_result_size == 0) {
3053 NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
3054 response_error = NECP_ERROR_INVALID_TLV;
3055 goto fail;
3056 }
3057 if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
3058 NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
3059 response_error = NECP_ERROR_INVALID_TLV;
3060 goto fail;
3061 }
3062 policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
3063 if (policy_result == NULL) {
3064 NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
3065 response_error = NECP_ERROR_INTERNAL;
3066 goto fail;
3067 }
3068 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
3069 if (error) {
3070 NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
3071 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3072 goto fail;
3073 }
3074 if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
3075 NECPLOG0(LOG_ERR, "Failed to validate policy result");
3076 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3077 goto fail;
3078 }
3079
3080 if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
3081 // Read route rules conditions
3082
3083 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3084 cursor >= 0;
3085 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3086 u_int32_t route_rule_size = 0;
3087 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3088 if (os_add_overflow(route_rules_array_size,
3089 (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
3090 &route_rules_array_size)) {
3091 NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
3092 response_error = NECP_ERROR_INVALID_TLV;
3093 goto fail;
3094 }
3095 }
3096
3097 if (route_rules_array_size == 0) {
3098 NECPLOG0(LOG_ERR, "Failed to get policy route rules");
3099 response_error = NECP_ERROR_INVALID_TLV;
3100 goto fail;
3101 }
3102 if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
3103 NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
3104 response_error = NECP_ERROR_INVALID_TLV;
3105 goto fail;
3106 }
3107 route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
3108 if (route_rules_array == NULL) {
3109 NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
3110 response_error = NECP_ERROR_INTERNAL;
3111 goto fail;
3112 }
3113
3114 route_rules_array_cursor = 0;
3115 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3116 cursor >= 0;
3117 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3118 u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
3119 u_int32_t route_rule_size = 0;
3120 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3121 if (route_rule_size > 0 &&
3122 (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
3123 // Add type
3124 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
3125 route_rules_array_cursor += sizeof(route_rule_type);
3126
3127 // Add length
3128 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
3129 route_rules_array_cursor += sizeof(route_rule_size);
3130
3131 // Add value
3132 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
3133
3134 if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3135 NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
3136 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3137 goto fail;
3138 }
3139
3140 if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3141 if (has_default_route_rule) {
3142 NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
3143 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3144 goto fail;
3145 }
3146 has_default_route_rule = TRUE;
3147 }
3148
3149 route_rules_array_cursor += route_rule_size;
3150 }
3151 }
3152 }
3153
3154 // Read policy conditions
3155 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3156 cursor >= 0;
3157 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3158 u_int32_t condition_size = 0;
3159 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3160
3161 if (condition_size > 0) {
3162 if (os_add_overflow(conditions_array_size,
3163 (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
3164 &conditions_array_size)) {
3165 NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
3166 response_error = NECP_ERROR_INVALID_TLV;
3167 goto fail;
3168 }
3169 }
3170 }
3171
3172 if (conditions_array_size == 0) {
3173 NECPLOG0(LOG_ERR, "Failed to get policy conditions");
3174 response_error = NECP_ERROR_INVALID_TLV;
3175 goto fail;
3176 }
3177 if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
3178 NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
3179 response_error = NECP_ERROR_INVALID_TLV;
3180 goto fail;
3181 }
3182 conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
3183 if (conditions_array == NULL) {
3184 NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
3185 response_error = NECP_ERROR_INTERNAL;
3186 goto fail;
3187 }
3188
3189 conditions_array_cursor = 0;
3190 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3191 cursor >= 0;
3192 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3193 u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
3194 u_int32_t condition_size = 0;
3195 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3196 if (condition_size > 0 &&
3197 (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
3198 // Add type
3199 memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
3200 conditions_array_cursor += sizeof(condition_type);
3201
3202 // Add length
3203 memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
3204 conditions_array_cursor += sizeof(condition_size);
3205
3206 // Add value
3207 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
3208 if (!necp_policy_condition_is_valid((conditions_array + conditions_array_cursor), condition_size, necp_policy_result_get_type_from_buffer(policy_result, policy_result_size))) {
3209 NECPLOG0(LOG_ERR, "Failed to validate policy condition");
3210 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3211 goto fail;
3212 }
3213
3214 if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
3215 has_default_condition = TRUE;
3216 } else {
3217 has_non_default_condition = TRUE;
3218 }
3219 if (has_default_condition && has_non_default_condition) {
3220 NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
3221 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3222 goto fail;
3223 }
3224
3225 if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
3226 has_application_condition = TRUE;
3227 }
3228
3229 if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
3230 has_real_application_condition = TRUE;
3231 }
3232
3233 if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
3234 requires_application_condition = TRUE;
3235 }
3236
3237 if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
3238 has_kernel_pid = TRUE;
3239 }
3240
3241 conditions_array_cursor += condition_size;
3242 }
3243 }
3244
3245 if (requires_application_condition && !has_application_condition) {
3246 NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
3247 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3248 goto fail;
3249 }
3250
3251 if (has_kernel_pid && !is_pass_skip) {
3252 NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
3253 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3254 goto fail;
3255 }
3256
3257 if ((policy = necp_policy_create(session, order, conditions_array, conditions_array_size, route_rules_array, route_rules_array_size, policy_result, policy_result_size)) == NULL) {
3258 response_error = NECP_ERROR_INTERNAL;
3259 goto fail;
3260 }
3261
3262 return policy->local_id;
3263
3264 fail:
3265 if (policy_result != NULL) {
3266 kfree_data_sized_by(policy_result, policy_result_size);
3267 }
3268 if (conditions_array != NULL) {
3269 kfree_data_sized_by(conditions_array, conditions_array_size);
3270 }
3271 if (route_rules_array != NULL) {
3272 kfree_data_sized_by(route_rules_array, route_rules_array_size);
3273 }
3274
3275 if (return_error != NULL) {
3276 *return_error = necp_get_posix_error_for_necp_error(response_error);
3277 }
3278 return 0;
3279 }
3280
3281 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)3282 necp_policy_get_new_id(struct necp_session *session)
3283 {
3284 session->last_policy_id++;
3285 if (session->last_policy_id < 1) {
3286 session->last_policy_id = 1;
3287 }
3288
3289 necp_policy_id newid = session->last_policy_id;
3290
3291 if (newid == 0) {
3292 NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
3293 return 0;
3294 }
3295
3296 return newid;
3297 }
3298
3299 /*
3300 * For the policy dump response this is the structure:
3301 *
3302 * <NECP_PACKET_HEADER>
3303 * {
3304 * type : NECP_TLV_POLICY_DUMP
3305 * length : ...
3306 * value :
3307 * {
3308 * {
3309 * type : NECP_TLV_POLICY_ID
3310 * len : ...
3311 * value : ...
3312 * }
3313 * {
3314 * type : NECP_TLV_POLICY_ORDER
3315 * len : ...
3316 * value : ...
3317 * }
3318 * {
3319 * type : NECP_TLV_POLICY_RESULT_STRING
3320 * len : ...
3321 * value : ...
3322 * }
3323 * {
3324 * type : NECP_TLV_POLICY_OWNER
3325 * len : ...
3326 * value : ...
3327 * }
3328 * {
3329 * type : NECP_TLV_POLICY_CONDITION
3330 * len : ...
3331 * value :
3332 * {
3333 * {
3334 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3335 * len : ...
3336 * value : ...
3337 * }
3338 * {
3339 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3340 * len : ...
3341 * value : ...
3342 * }
3343 * ...
3344 * }
3345 * }
3346 * }
3347 * }
3348 * {
3349 * type : NECP_TLV_POLICY_DUMP
3350 * length : ...
3351 * value :
3352 * {
3353 * {
3354 * type : NECP_TLV_POLICY_ID
3355 * len : ...
3356 * value : ...
3357 * }
3358 * {
3359 * type : NECP_TLV_POLICY_ORDER
3360 * len : ...
3361 * value : ...
3362 * }
3363 * {
3364 * type : NECP_TLV_POLICY_RESULT_STRING
3365 * len : ...
3366 * value : ...
3367 * }
3368 * {
3369 * type : NECP_TLV_POLICY_OWNER
3370 * len : ...
3371 * value : ...
3372 * }
3373 * {
3374 * type : NECP_TLV_POLICY_CONDITION
3375 * len : ...
3376 * value :
3377 * {
3378 * {
3379 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3380 * len : ...
3381 * value : ...
3382 * }
3383 * {
3384 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3385 * len : ...
3386 * value : ...
3387 * }
3388 * ...
3389 * }
3390 * }
3391 * }
3392 * }
3393 * ...
3394 */
3395 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3396 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3397 {
3398 struct necp_kernel_socket_policy * __single policy = NULL;
3399 int policy_i;
3400 int policy_count = 0;
3401 u_int8_t * __indexable * __indexable tlv_buffer_pointers = NULL;
3402 u_int32_t * __indexable tlv_buffer_lengths = NULL;
3403 u_int32_t total_tlv_len = 0;
3404 u_int8_t * __indexable result_buf = NULL;
3405 u_int8_t *result_buf_cursor = result_buf;
3406 char result_string[MAX_RESULT_STRING_LEN];
3407 char proc_name_string[MAXCOMLEN + 1];
3408
3409 int error_code = 0;
3410 bool error_occured = false;
3411 u_int32_t response_error = NECP_ERROR_INTERNAL;
3412
3413 #define REPORT_ERROR(error) error_occured = true; \
3414 response_error = error; \
3415 goto done
3416
3417 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
3418 REPORT_ERROR(error)
3419
3420 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3421 if (cred_result != 0) {
3422 NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3423 REPORT_ERROR(NECP_ERROR_INTERNAL);
3424 }
3425
3426 // LOCK
3427 lck_rw_lock_shared(&necp_kernel_policy_lock);
3428
3429 if (necp_debug) {
3430 NECPLOG0(LOG_DEBUG, "Gathering policies");
3431 }
3432
3433 policy_count = necp_kernel_application_policies_count;
3434
3435 tlv_buffer_pointers = kalloc_type(u_int8_t * __indexable, policy_count, M_WAITOK | Z_ZERO);
3436 if (tlv_buffer_pointers == NULL) {
3437 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3438 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3439 }
3440
3441 tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3442 if (tlv_buffer_lengths == NULL) {
3443 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3444 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3445 }
3446
3447 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3448 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3449
3450 memset(result_string, 0, MAX_RESULT_STRING_LEN);
3451 memset(proc_name_string, 0, MAXCOMLEN + 1);
3452
3453 necp_get_result_description(result_string, policy->result, policy->result_parameter);
3454 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3455
3456 u_int16_t proc_name_len = strbuflen(proc_name_string, sizeof(proc_name_string) - 1) + 1;
3457 u_int16_t result_string_len = strbuflen(result_string, sizeof(result_string) - 1) + 1;
3458
3459 if (necp_debug) {
3460 NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3461 }
3462
3463 u_int32_t total_allocated_bytes = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) + // NECP_TLV_POLICY_ID
3464 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) + // NECP_TLV_POLICY_ORDER
3465 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) + // NECP_TLV_POLICY_SESSION_ORDER
3466 sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len + // NECP_TLV_POLICY_RESULT_STRING
3467 sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len + // NECP_TLV_POLICY_OWNER
3468 sizeof(u_int8_t) + sizeof(u_int32_t); // NECP_TLV_POLICY_CONDITION
3469
3470 // We now traverse the condition_mask to see how much space we need to allocate
3471 u_int64_t condition_mask = policy->condition_mask;
3472 u_int64_t condition_negated_mask = policy->condition_negated_mask;
3473 u_int8_t num_conditions = 0;
3474 struct necp_string_id_mapping *account_id_entry = NULL;
3475 char if_name[IFXNAMSIZ];
3476 u_int32_t condition_tlv_length = 0;
3477 memset(if_name, 0, sizeof(if_name));
3478
3479 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3480 num_conditions++;
3481 } else {
3482 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3483 num_conditions++;
3484 }
3485 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3486 num_conditions++;
3487 }
3488 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3489 snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3490 condition_tlv_length += strbuflen(if_name, sizeof(if_name) - 1) + 1;
3491 num_conditions++;
3492 }
3493 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3494 condition_tlv_length += sizeof(policy->cond_protocol);
3495 num_conditions++;
3496 }
3497 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3498 condition_tlv_length += sizeof(uuid_t);
3499 num_conditions++;
3500 }
3501 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3502 condition_tlv_length += sizeof(uuid_t);
3503 num_conditions++;
3504 }
3505 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3506 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3507 u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3508 condition_tlv_length += domain_len;
3509 num_conditions++;
3510 }
3511 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3512 condition_tlv_length += sizeof(u_int32_t);
3513 num_conditions++;
3514 }
3515 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3516 u_int32_t url_len = strlen(policy->cond_url) + 1;
3517 condition_tlv_length += url_len;
3518 num_conditions++;
3519 }
3520 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3521 account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3522 u_int32_t account_id_len = 0;
3523 if (account_id_entry) {
3524 account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3525 }
3526 condition_tlv_length += account_id_len;
3527 num_conditions++;
3528 }
3529 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3530 condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3531 num_conditions++;
3532 }
3533 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3534 condition_tlv_length += sizeof(uid_t);
3535 num_conditions++;
3536 }
3537 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3538 condition_tlv_length += sizeof(uid_t);
3539 num_conditions++;
3540 }
3541 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3542 condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3543 num_conditions++;
3544 }
3545 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3546 num_conditions++;
3547 }
3548 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3549 u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3550 condition_tlv_length += entitlement_len;
3551 num_conditions++;
3552 }
3553 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3554 num_conditions++;
3555 }
3556 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3557 num_conditions++;
3558 }
3559 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3560 condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3561 num_conditions++;
3562 }
3563 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3564 condition_tlv_length += sizeof(policy->cond_local_networks_flags);
3565 num_conditions++;
3566 }
3567 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3568 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3569 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3570 } else {
3571 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3572 }
3573 num_conditions++;
3574 }
3575 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3576 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3577 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3578 } else {
3579 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3580 }
3581 num_conditions++;
3582 }
3583 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3584 condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3585 num_conditions++;
3586 }
3587 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3588 condition_tlv_length += sizeof(u_int32_t);
3589 num_conditions++;
3590 }
3591 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3592 num_conditions++;
3593 }
3594 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3595 num_conditions++;
3596 }
3597 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3598 u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3599 condition_tlv_length += identifier_len;
3600 num_conditions++;
3601 }
3602 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3603 condition_tlv_length += sizeof(u_int16_t);
3604 num_conditions++;
3605 }
3606 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3607 num_conditions++;
3608 }
3609 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3610 num_conditions++;
3611 }
3612 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3613 condition_tlv_length += sizeof(u_int16_t);
3614 num_conditions++;
3615 }
3616 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3617 condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3618 num_conditions++;
3619 }
3620 }
3621
3622 // These are for the condition TLVs (id, length, flags). The space for "value" is already accounted for above.
3623 condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int8_t));
3624 total_allocated_bytes += condition_tlv_length;
3625
3626 u_int8_t * __indexable tlv_buffer;
3627 tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3628 if (tlv_buffer == NULL) {
3629 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3630 continue;
3631 }
3632
3633 u_int8_t *cursor = tlv_buffer;
3634 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3635 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3636 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3637 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3638 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3639
3640 #define N_QUICK 256
3641 u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3642
3643 u_int8_t * __indexable cond_buf; // To be used for condition TLVs
3644 if (condition_tlv_length <= N_QUICK) {
3645 cond_buf = q_cond_buf;
3646 } else {
3647 cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3648 if (cond_buf == NULL) {
3649 NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3650 kfree_data(tlv_buffer, total_allocated_bytes);
3651 continue;
3652 }
3653 }
3654
3655 memset(cond_buf, 0, condition_tlv_length);
3656 u_int8_t *cond_buf_cursor = cond_buf;
3657 u_int8_t cond_flags = 0;
3658 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3659 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3660 } else {
3661 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3662 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3663 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ALL_INTERFACES, cond_flags, 0, "", cond_buf, condition_tlv_length);
3664 }
3665 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3666 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3667 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_HAS_CLIENT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3668 }
3669 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3670 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3671 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_NETWORKS, cond_flags, sizeof(policy->cond_local_networks_flags), &policy->cond_local_networks_flags, cond_buf, condition_tlv_length);
3672 }
3673 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3674 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3675 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE, cond_flags, strbuflen(if_name, sizeof(if_name) - 1) + 1,
3676 if_name, cond_buf, condition_tlv_length);
3677 }
3678 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3679 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3680 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_IP_PROTOCOL, cond_flags, sizeof(policy->cond_protocol), &policy->cond_protocol,
3681 cond_buf, condition_tlv_length);
3682 }
3683 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3684 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3685 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3686 if (entry != NULL) {
3687 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3688 cond_buf, condition_tlv_length);
3689 }
3690 }
3691 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3692 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3693 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3694 if (entry != NULL) {
3695 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3696 cond_buf, condition_tlv_length);
3697 }
3698 }
3699 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3700 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3701 cond_flags = ((condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) || (condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3702 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN, cond_flags, strlen(policy->cond_domain) + 1, __unsafe_null_terminated_to_indexable(policy->cond_domain), cond_buf, condition_tlv_length);
3703 }
3704 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3705 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3706 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN_FILTER, cond_flags, sizeof(policy->cond_domain_filter), &policy->cond_domain_filter,
3707 cond_buf, condition_tlv_length);
3708 }
3709 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3710 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_URL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3711 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_URL, cond_flags, strlen(policy->cond_url) + 1, __unsafe_null_terminated_to_indexable(policy->cond_url), cond_buf, condition_tlv_length);
3712 }
3713 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3714 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3715 if (account_id_entry != NULL) {
3716 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ACCOUNT, cond_flags, strlen(account_id_entry->string) + 1, __unsafe_null_terminated_to_indexable(account_id_entry->string), cond_buf, condition_tlv_length);
3717 }
3718 }
3719 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3720 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3721 uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3722 memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3723 memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3724 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PID, cond_flags, sizeof(pid_buffer), &pid_buffer,
3725 cond_buf, condition_tlv_length);
3726 }
3727 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3728 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3729 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_UID, cond_flags, sizeof(policy->cond_uid), &policy->cond_uid,
3730 cond_buf, condition_tlv_length);
3731 }
3732 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3733 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3734 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_UID, cond_flags, sizeof(policy->cond_real_uid), &policy->cond_real_uid,
3735 cond_buf, condition_tlv_length);
3736 }
3737 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3738 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3739 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_TRAFFIC_CLASS, cond_flags, sizeof(policy->cond_traffic_class), &policy->cond_traffic_class,
3740 cond_buf, condition_tlv_length);
3741 }
3742 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3743 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3744 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, 0, "",
3745 cond_buf, condition_tlv_length);
3746 }
3747 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3748 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3749 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, strlen(policy->cond_custom_entitlement) + 1, __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement), cond_buf, condition_tlv_length);
3750 }
3751 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3752 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3753 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PLATFORM_BINARY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3754 }
3755 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3756 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3757 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3758 }
3759 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3760 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SDK_VERSION) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3761 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION, cond_flags,
3762 sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3763 cond_buf, condition_tlv_length);
3764 }
3765 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3766 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3767 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3768 struct necp_policy_condition_addr_range range;
3769 memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3770 memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3771 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, cond_flags, sizeof(range), &range,
3772 cond_buf, condition_tlv_length);
3773 } else {
3774 struct necp_policy_condition_addr addr;
3775 addr.prefix = policy->cond_local_prefix;
3776 memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3777 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, cond_flags, sizeof(addr), &addr,
3778 cond_buf, condition_tlv_length);
3779 }
3780 }
3781 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3782 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3783 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3784 struct necp_policy_condition_addr_range range;
3785 memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3786 memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3787 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, cond_flags, sizeof(range), &range,
3788 cond_buf, condition_tlv_length);
3789 } else {
3790 struct necp_policy_condition_addr addr;
3791 addr.prefix = policy->cond_remote_prefix;
3792 memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3793 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, cond_flags, sizeof(addr), &addr,
3794 cond_buf, condition_tlv_length);
3795 }
3796 }
3797 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3798 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3799 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE, cond_flags,
3800 sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3801 cond_buf, condition_tlv_length);
3802 }
3803 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3804 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3805 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_CLIENT_FLAGS, cond_flags, sizeof(policy->cond_client_flags), &policy->cond_client_flags, cond_buf, condition_tlv_length);
3806 }
3807 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3808 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3809 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3810 }
3811 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3812 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3813 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3814 }
3815 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3816 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3817 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SIGNING_IDENTIFIER, cond_flags, strlen(policy->cond_signing_identifier) + 1, __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier), cond_buf, condition_tlv_length);
3818 }
3819 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3820 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3821 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PACKET_FILTER_TAGS, cond_flags, sizeof(policy->cond_packet_filter_tags), &policy->cond_packet_filter_tags, cond_buf, condition_tlv_length);
3822 }
3823 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3824 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3825 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK, cond_flags, 0, "", cond_buf, condition_tlv_length);
3826 }
3827 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3828 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3829 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3830 }
3831 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3832 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3833 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SCHEME_PORT, cond_flags, sizeof(policy->cond_scheme_port), &policy->cond_scheme_port, cond_buf, condition_tlv_length);
3834 }
3835 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3836 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3837 uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3838 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3839 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3840 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3841 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, cond_flags, sizeof(flags), &flags,
3842 cond_buf, condition_tlv_length);
3843 }
3844 }
3845
3846 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3847 if (cond_buf != q_cond_buf) {
3848 kfree_data(cond_buf, condition_tlv_length);
3849 }
3850
3851 tlv_buffer_pointers[policy_i] = tlv_buffer;
3852 tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3853
3854 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
3855 total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3856 }
3857
3858 // UNLOCK
3859 lck_rw_done(&necp_kernel_policy_lock);
3860
3861 // Copy out
3862 if (out_buffer != 0) {
3863 if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3864 NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3865 REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3866 }
3867
3868 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3869 result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3870 if (result_buf == NULL) {
3871 NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3872 REPORT_ERROR(NECP_ERROR_INTERNAL);
3873 }
3874
3875 // Add four bytes for total length at the start
3876 memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3877
3878 // Copy the TLVs
3879 result_buf_cursor = result_buf + sizeof(u_int32_t);
3880 for (int i = 0; i < policy_count; i++) {
3881 if (tlv_buffer_pointers[i] != NULL) {
3882 result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3883 result_buf, total_tlv_len + sizeof(u_int32_t));
3884 }
3885 }
3886
3887 int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3888 if (copy_error) {
3889 NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3890 REPORT_ERROR(NECP_ERROR_INTERNAL);
3891 }
3892 }
3893
3894 done:
3895
3896 if (error_occured) {
3897 error_code = necp_get_posix_error_for_necp_error(response_error);
3898 }
3899
3900 if (result_buf != NULL) {
3901 kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3902 }
3903
3904 if (tlv_buffer_pointers != NULL) {
3905 for (int i = 0; i < policy_count; i++) {
3906 if (tlv_buffer_pointers[i] != NULL) {
3907 kfree_data_addr(tlv_buffer_pointers[i]);
3908 tlv_buffer_pointers[i] = NULL;
3909 }
3910 }
3911 kfree_type(u_int8_t * __indexable, policy_count, tlv_buffer_pointers);
3912 }
3913
3914 if (tlv_buffer_lengths != NULL) {
3915 kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3916 }
3917 #undef N_QUICK
3918 #undef RESET_COND_BUF
3919 #undef REPORT_ERROR
3920 #undef UNLOCK_AND_REPORT_ERROR
3921
3922 return error_code;
3923 }
3924
3925 static struct necp_session_policy *
necp_policy_create(struct necp_session * session,necp_policy_order order,u_int8_t * __sized_by (conditions_array_size)conditions_array,u_int32_t conditions_array_size,u_int8_t * __sized_by (route_rules_array_size)route_rules_array,u_int32_t route_rules_array_size,u_int8_t * __sized_by (result_size)result,u_int32_t result_size)3926 necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t * __sized_by(conditions_array_size)conditions_array, u_int32_t conditions_array_size, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, u_int8_t *__sized_by(result_size)result, u_int32_t result_size)
3927 {
3928 struct necp_session_policy *new_policy = NULL;
3929 struct necp_session_policy *tmp_policy = NULL;
3930
3931 if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3932 goto done;
3933 }
3934
3935 new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3936 new_policy->applied = FALSE;
3937 new_policy->pending_deletion = FALSE;
3938 new_policy->pending_update = FALSE;
3939 new_policy->order = order;
3940 new_policy->conditions = conditions_array;
3941 new_policy->conditions_size = conditions_array_size;
3942 new_policy->route_rules = route_rules_array;
3943 new_policy->route_rules_size = route_rules_array_size;
3944 new_policy->result = result;
3945 new_policy->result_size = result_size;
3946 new_policy->local_id = necp_policy_get_new_id(session);
3947
3948 LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3949
3950 session->dirty = TRUE;
3951
3952 if (necp_debug) {
3953 NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3954 }
3955 done:
3956 return new_policy;
3957 }
3958
3959 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3960 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3961 {
3962 struct necp_session_policy *policy = NULL;
3963 if (policy_id == 0) {
3964 return NULL;
3965 }
3966
3967 LIST_FOREACH(policy, &session->policies, chain) {
3968 if (policy->local_id == policy_id) {
3969 return policy;
3970 }
3971 }
3972
3973 return NULL;
3974 }
3975
3976 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3977 necp_policy_get_result_type(struct necp_session_policy *policy)
3978 {
3979 return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3980 }
3981
3982 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3983 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3984 {
3985 return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3986 }
3987
3988 static bool
necp_policy_get_result_parameter(struct necp_session_policy * policy,u_int8_t * __sized_by (parameter_buffer_length)parameter_buffer,u_int32_t parameter_buffer_length)3989 necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t * __sized_by(parameter_buffer_length)parameter_buffer, u_int32_t parameter_buffer_length)
3990 {
3991 if (policy) {
3992 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3993 if (parameter_buffer_length >= parameter_length) {
3994 u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3995 if (parameter && parameter_buffer) {
3996 memcpy(parameter_buffer, parameter, parameter_length);
3997 return TRUE;
3998 }
3999 }
4000 }
4001
4002 return FALSE;
4003 }
4004
4005 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)4006 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
4007 {
4008 if (session == NULL || policy == NULL) {
4009 return FALSE;
4010 }
4011
4012 policy->pending_deletion = TRUE;
4013 session->dirty = TRUE;
4014
4015 if (necp_debug) {
4016 NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
4017 }
4018 return TRUE;
4019 }
4020
4021 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)4022 necp_policy_mark_all_for_deletion(struct necp_session *session)
4023 {
4024 struct necp_session_policy *policy = NULL;
4025 struct necp_session_policy *temp_policy = NULL;
4026
4027 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4028 necp_policy_mark_for_deletion(session, policy);
4029 }
4030
4031 return TRUE;
4032 }
4033
4034 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)4035 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
4036 {
4037 if (session == NULL || policy == NULL) {
4038 return FALSE;
4039 }
4040
4041 LIST_REMOVE(policy, chain);
4042
4043 if (policy->result) {
4044 kfree_data_sized_by(policy->result, policy->result_size);
4045 policy->result = NULL;
4046 policy->result_size = 0;
4047 }
4048
4049 if (policy->conditions) {
4050 kfree_data_sized_by(policy->conditions, policy->conditions_size);
4051 policy->conditions = NULL;
4052 policy->conditions_size = 0;
4053 }
4054
4055 if (policy->route_rules) {
4056 kfree_data_sized_by(policy->route_rules, policy->route_rules_size);
4057 policy->route_rules = NULL;
4058 policy->route_rules_size = 0;
4059 }
4060
4061 zfree(necp_session_policy_zone, policy);
4062
4063 if (necp_debug) {
4064 NECPLOG0(LOG_DEBUG, "Removed NECP policy");
4065 }
4066 return TRUE;
4067 }
4068
4069 static bool
necp_policy_unapply(struct necp_session_policy * policy)4070 necp_policy_unapply(struct necp_session_policy *policy)
4071 {
4072 int i = 0;
4073 if (policy == NULL) {
4074 return FALSE;
4075 }
4076
4077 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4078
4079 // Release local uuid mappings
4080 if (!uuid_is_null(policy->applied_app_uuid)) {
4081 bool removed_mapping = FALSE;
4082 if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
4083 necp_uuid_app_id_mappings_dirty = TRUE;
4084 necp_num_uuid_app_id_mappings--;
4085 }
4086 uuid_clear(policy->applied_app_uuid);
4087 }
4088 if (!uuid_is_null(policy->applied_real_app_uuid)) {
4089 necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
4090 uuid_clear(policy->applied_real_app_uuid);
4091 }
4092 if (!uuid_is_null(policy->applied_result_uuid)) {
4093 necp_remove_uuid_service_id_mapping(policy->applied_result_uuid);
4094 uuid_clear(policy->applied_result_uuid);
4095 }
4096
4097 // Release string mappings
4098 if (policy->applied_account != NULL) {
4099 necp_remove_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(policy->applied_account));
4100 kfree_data_sized_by(policy->applied_account, policy->applied_account_size);
4101 policy->applied_account = NULL;
4102 policy->applied_account_size = 0;
4103 }
4104
4105 // Release route rule
4106 if (policy->applied_route_rules_id != 0) {
4107 necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
4108 policy->applied_route_rules_id = 0;
4109 }
4110
4111 // Remove socket policies
4112 for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
4113 if (policy->kernel_socket_policies[i] != 0) {
4114 necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
4115 policy->kernel_socket_policies[i] = 0;
4116 }
4117 }
4118
4119 // Remove IP output policies
4120 for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
4121 if (policy->kernel_ip_output_policies[i] != 0) {
4122 necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
4123 policy->kernel_ip_output_policies[i] = 0;
4124 }
4125 }
4126
4127 policy->applied = FALSE;
4128
4129 return TRUE;
4130 }
4131
4132 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
4133 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
4134 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
4135 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
4136 struct necp_policy_result_ip_tunnel {
4137 u_int32_t secondary_result;
4138 char interface_name[IFXNAMSIZ];
4139 } __attribute__((__packed__));
4140
4141 struct necp_policy_result_service {
4142 uuid_t identifier;
4143 u_int32_t data;
4144 } __attribute__((__packed__));
4145
4146 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy)4147 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
4148 {
4149 bool socket_only_conditions = FALSE;
4150 bool socket_ip_conditions = FALSE;
4151
4152 bool socket_layer_non_id_conditions = FALSE;
4153 bool ip_output_layer_non_id_conditions = FALSE;
4154 bool ip_output_layer_non_id_only = FALSE;
4155 bool ip_output_layer_id_condition = FALSE;
4156 bool ip_output_layer_tunnel_condition_from_id = FALSE;
4157 bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
4158 necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
4159
4160 u_int64_t master_condition_mask = 0;
4161 u_int64_t master_condition_negated_mask = 0;
4162 ifnet_t __single cond_bound_interface = NULL;
4163 u_int32_t cond_account_id = 0;
4164 char *cond_domain __null_terminated = NULL;
4165 u_int32_t cond_domain_filter = 0;
4166 char *cond_url __null_terminated = NULL;
4167 char *cond_custom_entitlement __null_terminated = NULL;
4168 char *cond_signing_identifier __null_terminated = NULL;
4169 pid_t cond_pid = 0;
4170 int32_t cond_pid_version = 0;
4171 uid_t cond_uid = 0;
4172 uid_t cond_real_uid = 0;
4173 necp_app_id cond_app_id = 0;
4174 necp_app_id cond_real_app_id = 0;
4175 struct necp_policy_condition_tc_range cond_traffic_class;
4176 cond_traffic_class.start_tc = 0;
4177 cond_traffic_class.end_tc = 0;
4178 u_int16_t cond_protocol = 0;
4179 union necp_sockaddr_union cond_local_start;
4180 union necp_sockaddr_union cond_local_end;
4181 u_int8_t cond_local_prefix = 0;
4182 union necp_sockaddr_union cond_remote_start;
4183 union necp_sockaddr_union cond_remote_end;
4184 u_int8_t cond_remote_prefix = 0;
4185 u_int32_t cond_client_flags = 0;
4186 u_int8_t cond_local_networks_flags = 0;
4187 u_int32_t offset = 0;
4188 u_int8_t ultimate_result = 0;
4189 u_int32_t secondary_result = 0;
4190 struct necp_policy_condition_agent_type cond_agent_type = {};
4191 struct necp_policy_condition_sdk_version cond_sdk_version = {};
4192 u_int16_t cond_packet_filter_tags = 0;
4193 u_int16_t cond_scheme_port = 0;
4194 u_int32_t cond_bound_interface_flags = 0;
4195 u_int32_t cond_bound_interface_eflags = 0;
4196 u_int32_t cond_bound_interface_xflags = 0;
4197 necp_kernel_policy_result_parameter secondary_result_parameter;
4198 memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
4199 u_int32_t cond_last_interface_index = 0;
4200 necp_kernel_policy_result_parameter ultimate_result_parameter;
4201 memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
4202
4203 if (policy == NULL) {
4204 return FALSE;
4205 }
4206
4207 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4208
4209 // Process conditions
4210 while (offset < policy->conditions_size) {
4211 u_int32_t length = 0;
4212 u_int8_t * __indexable value = necp_buffer_get_tlv_value(policy->conditions, policy->conditions_size, offset, &length);
4213
4214 u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
4215 u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
4216 bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
4217 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
4218 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
4219 switch (condition_type) {
4220 case NECP_POLICY_CONDITION_DEFAULT: {
4221 socket_ip_conditions = TRUE;
4222 break;
4223 }
4224 case NECP_POLICY_CONDITION_ALL_INTERFACES: {
4225 master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
4226 socket_ip_conditions = TRUE;
4227 break;
4228 }
4229 case NECP_POLICY_CONDITION_HAS_CLIENT: {
4230 master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
4231 socket_only_conditions = TRUE;
4232 break;
4233 }
4234 case NECP_POLICY_CONDITION_ENTITLEMENT: {
4235 if (condition_length > 0) {
4236 if (cond_custom_entitlement == NULL) {
4237 cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
4238 if (cond_custom_entitlement != NULL) {
4239 master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
4240 socket_only_conditions = TRUE;
4241 }
4242 }
4243 } else {
4244 master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
4245 socket_only_conditions = TRUE;
4246 }
4247 break;
4248 }
4249 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
4250 master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4251 if (condition_is_negative) {
4252 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4253 }
4254 socket_only_conditions = TRUE;
4255 break;
4256 }
4257 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
4258 master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
4259 socket_only_conditions = TRUE;
4260 break;
4261 }
4262 case NECP_POLICY_CONDITION_SDK_VERSION: {
4263 if (condition_length >= sizeof(cond_sdk_version)) {
4264 master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
4265 memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
4266 socket_only_conditions = TRUE;
4267 }
4268 break;
4269 }
4270 case NECP_POLICY_CONDITION_DOMAIN: {
4271 // Make sure there is only one such rule
4272 if (condition_length > 0 && cond_domain == NULL) {
4273 const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
4274
4275 u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
4276 cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
4277 if (cond_domain != NULL) {
4278 master_condition_mask |= mask_value;
4279 if (condition_is_negative) {
4280 master_condition_negated_mask |= mask_value;
4281 }
4282 socket_only_conditions = TRUE;
4283 }
4284 }
4285 break;
4286 }
4287 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
4288 // Make sure there is only one such rule
4289 if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
4290 memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
4291 if (cond_domain_filter != 0) {
4292 master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4293 if (condition_is_negative) {
4294 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4295 }
4296 socket_only_conditions = TRUE;
4297 }
4298 }
4299 break;
4300 }
4301 case NECP_POLICY_CONDITION_URL: {
4302 // Make sure there is only one such rule
4303 if (condition_length > 0 && cond_url == NULL) {
4304 u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
4305 cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
4306 if (cond_url != NULL) {
4307 master_condition_mask |= mask_value;
4308 if (condition_is_negative) {
4309 master_condition_negated_mask |= mask_value;
4310 }
4311 socket_only_conditions = TRUE;
4312 }
4313 }
4314 break;
4315 }
4316 case NECP_POLICY_CONDITION_ACCOUNT: {
4317 // Make sure there is only one such rule
4318 if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
4319 size_t string_buffer_size = 0;
4320 char * __sized_by(string_buffer_size) string = NULL;
4321 string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
4322 string_buffer_size = condition_length + 1;
4323 if (string != NULL) {
4324 memcpy(string, condition_value, condition_length);
4325 string[condition_length] = 0;
4326 cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(string, &string[condition_length]));
4327 if (cond_account_id != 0) {
4328 policy->applied_account = string; // Save the string in parent policy
4329 policy->applied_account_size = string_buffer_size;
4330 master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4331 if (condition_is_negative) {
4332 master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4333 }
4334 socket_only_conditions = TRUE;
4335 } else {
4336 kfree_data_sized_by(string, string_buffer_size);
4337 }
4338 }
4339 }
4340 break;
4341 }
4342 case NECP_POLICY_CONDITION_APPLICATION: {
4343 // Make sure there is only one such rule, because we save the uuid in the policy
4344 if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
4345 bool allocated_mapping = FALSE;
4346 uuid_t application_uuid;
4347 memcpy(application_uuid, condition_value, sizeof(uuid_t));
4348 cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
4349 if (cond_app_id != 0) {
4350 if (allocated_mapping) {
4351 necp_uuid_app_id_mappings_dirty = TRUE;
4352 necp_num_uuid_app_id_mappings++;
4353 }
4354 uuid_copy(policy->applied_app_uuid, application_uuid);
4355 master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
4356 if (condition_is_negative) {
4357 master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
4358 }
4359 socket_only_conditions = TRUE;
4360 }
4361 }
4362 break;
4363 }
4364 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
4365 // Make sure there is only one such rule, because we save the uuid in the policy
4366 if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
4367 uuid_t real_application_uuid;
4368 memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
4369 cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
4370 if (cond_real_app_id != 0) {
4371 uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
4372 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4373 if (condition_is_negative) {
4374 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4375 }
4376 socket_only_conditions = TRUE;
4377 }
4378 }
4379 break;
4380 }
4381 case NECP_POLICY_CONDITION_PID: {
4382 if (condition_length >= sizeof(pid_t)) {
4383 master_condition_mask |= NECP_KERNEL_CONDITION_PID;
4384 if (condition_is_negative) {
4385 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
4386 }
4387 memcpy(&cond_pid, condition_value, sizeof(cond_pid));
4388 if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
4389 memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
4390 }
4391 socket_only_conditions = TRUE;
4392 }
4393 break;
4394 }
4395 case NECP_POLICY_CONDITION_UID: {
4396 if (condition_length >= sizeof(uid_t)) {
4397 master_condition_mask |= NECP_KERNEL_CONDITION_UID;
4398 if (condition_is_negative) {
4399 master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
4400 }
4401 memcpy(&cond_uid, condition_value, sizeof(cond_uid));
4402 socket_only_conditions = TRUE;
4403 }
4404 break;
4405 }
4406 case NECP_POLICY_CONDITION_REAL_UID: {
4407 if (condition_length >= sizeof(uid_t)) {
4408 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4409 if (condition_is_negative) {
4410 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4411 }
4412 memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
4413 socket_only_conditions = TRUE;
4414 }
4415 break;
4416 }
4417 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
4418 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
4419 master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4420 if (condition_is_negative) {
4421 master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4422 }
4423 memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
4424 socket_only_conditions = TRUE;
4425 }
4426 break;
4427 }
4428 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4429 if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4430 char interface_name[IFXNAMSIZ];
4431 memcpy(interface_name, condition_value, condition_length);
4432 interface_name[condition_length - 1] = 0; // Make sure the string is NULL terminated
4433 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[condition_length - 1]), &cond_bound_interface) == 0) {
4434 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4435 if (condition_is_negative) {
4436 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4437 }
4438 }
4439 socket_ip_conditions = TRUE;
4440 }
4441 break;
4442 }
4443 case NECP_POLICY_CONDITION_IP_PROTOCOL:
4444 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4445 if (condition_length >= sizeof(u_int16_t)) {
4446 master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4447 if (condition_is_negative) {
4448 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4449 }
4450 memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4451 if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4452 socket_only_conditions = TRUE;
4453 } else {
4454 socket_ip_conditions = TRUE;
4455 }
4456 }
4457 break;
4458 }
4459 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4460 if (condition_is_negative) {
4461 master_condition_negated_mask |= NECP_POLICY_CONDITION_LOCAL_NETWORKS;
4462 }
4463 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4464 socket_ip_conditions = TRUE;
4465 if (condition_length >= sizeof(u_int8_t)) {
4466 memcpy(&cond_local_networks_flags, condition_value, sizeof(cond_local_networks_flags));
4467 }
4468 break;
4469 }
4470 case NECP_POLICY_CONDITION_LOCAL_ADDR:
4471 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4472 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4473 if (!necp_address_is_valid(&address_struct->address.sa)) {
4474 break;
4475 }
4476
4477 cond_local_prefix = address_struct->prefix;
4478 memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4479 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4480 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4481 if (condition_is_negative) {
4482 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4483 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4484 }
4485 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4486 socket_only_conditions = TRUE;
4487 } else {
4488 socket_ip_conditions = TRUE;
4489 }
4490 break;
4491 }
4492 case NECP_POLICY_CONDITION_REMOTE_ADDR:
4493 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4494 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4495 if (!necp_address_is_valid(&address_struct->address.sa)) {
4496 break;
4497 }
4498
4499 cond_remote_prefix = address_struct->prefix;
4500 memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4501 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4502 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4503 if (condition_is_negative) {
4504 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4505 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4506 }
4507 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4508 socket_only_conditions = TRUE;
4509 } else {
4510 socket_ip_conditions = TRUE;
4511 }
4512 break;
4513 }
4514 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4515 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4516 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4517 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4518 !necp_address_is_valid(&address_struct->end_address.sa)) {
4519 break;
4520 }
4521
4522 memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4523 memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4524 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4525 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4526 if (condition_is_negative) {
4527 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4528 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4529 }
4530 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4531 socket_only_conditions = TRUE;
4532 } else {
4533 socket_ip_conditions = TRUE;
4534 }
4535 break;
4536 }
4537 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4538 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4539 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4540 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4541 !necp_address_is_valid(&address_struct->end_address.sa)) {
4542 break;
4543 }
4544
4545 memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4546 memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4547 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4548 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4549 if (condition_is_negative) {
4550 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4551 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4552 }
4553 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4554 socket_only_conditions = TRUE;
4555 } else {
4556 socket_ip_conditions = TRUE;
4557 }
4558 break;
4559 }
4560 case NECP_POLICY_CONDITION_AGENT_TYPE: {
4561 if (condition_length >= sizeof(cond_agent_type)) {
4562 master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4563 memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4564 socket_only_conditions = TRUE;
4565 }
4566 break;
4567 }
4568 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4569 if (condition_is_negative) {
4570 master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4571 }
4572 master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4573 socket_only_conditions = TRUE;
4574 if (condition_length >= sizeof(u_int32_t)) {
4575 memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4576 } else {
4577 // Empty means match on fallback traffic
4578 cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4579 }
4580 break;
4581 }
4582 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4583 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4584 if (condition_is_negative) {
4585 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4586 }
4587 socket_only_conditions = TRUE;
4588 break;
4589 }
4590 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4591 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4592 if (condition_is_negative) {
4593 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4594 }
4595 socket_only_conditions = TRUE;
4596 break;
4597 }
4598 case NECP_POLICY_CONDITION_SCHEME_PORT: {
4599 master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4600 if (condition_is_negative) {
4601 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4602 }
4603 memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4604 socket_ip_conditions = TRUE;
4605 break;
4606 }
4607 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4608 if (condition_length > 0) {
4609 if (cond_signing_identifier == NULL) {
4610 cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4611 if (cond_signing_identifier != NULL) {
4612 master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4613 socket_only_conditions = TRUE;
4614 if (condition_is_negative) {
4615 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4616 }
4617 }
4618 }
4619 }
4620 break;
4621 }
4622 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4623 if (condition_length >= sizeof(u_int16_t)) {
4624 master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4625 if (condition_is_negative) {
4626 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4627 }
4628 memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4629 socket_ip_conditions = TRUE;
4630 }
4631 break;
4632 }
4633 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4634 master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4635 if (condition_is_negative) {
4636 master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4637 }
4638 socket_only_conditions = TRUE;
4639 break;
4640 }
4641 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4642 master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4643 if (condition_is_negative) {
4644 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4645 }
4646 socket_only_conditions = TRUE;
4647 break;
4648 }
4649 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4650 if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4651 u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4652 memcpy(&flags, condition_value, sizeof(flags));
4653 cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4654 cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4655 cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4656 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4657 if (condition_is_negative) {
4658 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4659 }
4660 socket_ip_conditions = TRUE;
4661 }
4662 break;
4663 }
4664 default: {
4665 break;
4666 }
4667 }
4668
4669 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4670 }
4671
4672 // Process result
4673 ultimate_result = necp_policy_get_result_type(policy);
4674 switch (ultimate_result) {
4675 case NECP_POLICY_RESULT_PASS: {
4676 u_int32_t pass_flags = 0;
4677 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4678 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4679 ultimate_result_parameter.pass_flags = pass_flags;
4680 }
4681 }
4682 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4683 socket_layer_non_id_conditions = TRUE;
4684 ip_output_layer_id_condition = TRUE;
4685 } else if (socket_ip_conditions) {
4686 socket_layer_non_id_conditions = TRUE;
4687 ip_output_layer_id_condition = TRUE;
4688 ip_output_layer_non_id_conditions = TRUE;
4689 }
4690 break;
4691 }
4692 case NECP_POLICY_RESULT_DROP: {
4693 u_int32_t drop_flags = 0;
4694 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4695 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4696 ultimate_result_parameter.drop_flags = drop_flags;
4697 }
4698 }
4699 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4700 socket_layer_non_id_conditions = TRUE;
4701 } else if (socket_ip_conditions) {
4702 socket_layer_non_id_conditions = TRUE;
4703 ip_output_layer_non_id_conditions = TRUE;
4704 ip_output_layer_non_id_only = TRUE; // Only apply drop to packets that didn't go through socket layer
4705 }
4706 break;
4707 }
4708 case NECP_POLICY_RESULT_SKIP: {
4709 u_int32_t skip_policy_order = 0;
4710 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4711 ultimate_result_parameter.skip_policy_order = skip_policy_order;
4712 }
4713
4714 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4715 socket_layer_non_id_conditions = TRUE;
4716 ip_output_layer_id_condition = TRUE;
4717 } else if (socket_ip_conditions) {
4718 socket_layer_non_id_conditions = TRUE;
4719 ip_output_layer_non_id_conditions = TRUE;
4720 }
4721 break;
4722 }
4723 case NECP_POLICY_RESULT_SOCKET_DIVERT:
4724 case NECP_POLICY_RESULT_SOCKET_FILTER: {
4725 u_int32_t control_unit = 0;
4726 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4727 ultimate_result_parameter.flow_divert_control_unit = control_unit;
4728 }
4729 socket_layer_non_id_conditions = TRUE;
4730 break;
4731 }
4732 case NECP_POLICY_RESULT_IP_TUNNEL: {
4733 struct necp_policy_result_ip_tunnel tunnel_parameters;
4734 u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4735 if (tunnel_parameters_length > sizeof(u_int32_t) &&
4736 tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4737 necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4738 ifnet_t __single tunnel_interface = NULL;
4739 tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0; // Make sure the string is NULL terminated
4740 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4741 ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4742 ifnet_release(tunnel_interface);
4743 }
4744
4745 secondary_result = tunnel_parameters.secondary_result;
4746 if (secondary_result) {
4747 cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4748 }
4749 }
4750
4751 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4752 socket_layer_non_id_conditions = TRUE;
4753 ip_output_layer_id_condition = TRUE;
4754 if (secondary_result) {
4755 ip_output_layer_tunnel_condition_from_id = TRUE;
4756 }
4757 } else if (socket_ip_conditions) {
4758 socket_layer_non_id_conditions = TRUE;
4759 ip_output_layer_id_condition = TRUE;
4760 ip_output_layer_non_id_conditions = TRUE;
4761 if (secondary_result) {
4762 ip_output_layer_tunnel_condition_from_id = TRUE;
4763 ip_output_layer_tunnel_condition_from_non_id = TRUE;
4764 }
4765 }
4766 break;
4767 }
4768 case NECP_POLICY_RESULT_USE_NETAGENT:
4769 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4770 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4771 uuid_t netagent_uuid;
4772 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4773 ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
4774 if (ultimate_result_parameter.netagent_id != 0) {
4775 uuid_copy(policy->applied_result_uuid, netagent_uuid);
4776 socket_layer_non_id_conditions = TRUE;
4777 }
4778 }
4779 break;
4780 }
4781 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4782 u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4783 if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4784 char interface_name[IFXNAMSIZ];
4785 ifnet_t __single scope_interface = NULL;
4786 necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4787 interface_name[interface_name_length - 1] = 0; // Make sure the string is NULL terminated
4788 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4789 ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4790 socket_layer_non_id_conditions = TRUE;
4791 ifnet_release(scope_interface);
4792 }
4793 }
4794 break;
4795 }
4796 case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4797 socket_layer_non_id_conditions = TRUE;
4798 break;
4799 }
4800 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4801 socket_layer_non_id_conditions = TRUE;
4802 break;
4803 }
4804 case NECP_POLICY_RESULT_ROUTE_RULES: {
4805 if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4806 bool has_socket_only_actions = FALSE;
4807 u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4808 if (route_rule_id > 0) {
4809 policy->applied_route_rules_id = route_rule_id;
4810 ultimate_result_parameter.route_rule_id = route_rule_id;
4811 if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4812 socket_layer_non_id_conditions = TRUE;
4813 } else if (socket_ip_conditions) {
4814 socket_layer_non_id_conditions = TRUE;
4815 ip_output_layer_non_id_conditions = TRUE;
4816 ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4817 }
4818 }
4819 }
4820 break;
4821 }
4822 default: {
4823 break;
4824 }
4825 }
4826
4827 if (socket_layer_non_id_conditions) {
4828 necp_kernel_policy_id policy_id = necp_kernel_socket_policy_add(policy->order, session->session_order, session->proc_pid, master_condition_mask, master_condition_negated_mask, cond_app_id, cond_real_app_id, cond_custom_entitlement, cond_account_id, cond_domain, cond_domain_filter, cond_url, cond_pid, cond_pid_version, cond_uid, cond_real_uid, cond_bound_interface, cond_traffic_class, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, &cond_agent_type, &cond_sdk_version, cond_client_flags, cond_signing_identifier, cond_packet_filter_tags, cond_scheme_port, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, ultimate_result, ultimate_result_parameter);
4829
4830 if (policy_id == 0) {
4831 NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4832 goto fail;
4833 }
4834
4835 cond_ip_output_layer_id = policy_id;
4836 policy->kernel_socket_policies[0] = policy_id;
4837 }
4838
4839 if (ip_output_layer_non_id_conditions) {
4840 u_int64_t condition_mask = master_condition_mask;
4841 if (ip_output_layer_non_id_only) {
4842 condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4843 }
4844
4845 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS, session->session_order, session->proc_pid, condition_mask, master_condition_negated_mask, NECP_KERNEL_POLICY_ID_NONE, cond_bound_interface, 0, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, cond_packet_filter_tags, cond_scheme_port, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, ultimate_result, ultimate_result_parameter);
4846
4847 if (policy_id == 0) {
4848 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4849 goto fail;
4850 }
4851
4852 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4853 }
4854
4855 if (ip_output_layer_id_condition) {
4856 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION, session->session_order, session->proc_pid, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_ALL_INTERFACES, 0, cond_ip_output_layer_id, NULL, 0, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, ultimate_result, ultimate_result_parameter);
4857
4858 if (policy_id == 0) {
4859 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4860 goto fail;
4861 }
4862
4863 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4864 }
4865
4866 // Extra policies for IP Output tunnels for when packets loop back
4867 if (ip_output_layer_tunnel_condition_from_id) {
4868 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION, session->session_order, session->proc_pid, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_ALL_INTERFACES, 0, policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS], NULL, cond_last_interface_index, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, secondary_result, secondary_result_parameter);
4869
4870 if (policy_id == 0) {
4871 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4872 goto fail;
4873 }
4874
4875 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4876 }
4877
4878 if (ip_output_layer_tunnel_condition_from_id) {
4879 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION, session->session_order, session->proc_pid, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_ALL_INTERFACES, 0, policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION], NULL, cond_last_interface_index, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, secondary_result, secondary_result_parameter);
4880
4881 if (policy_id == 0) {
4882 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4883 goto fail;
4884 }
4885
4886 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4887 }
4888
4889 policy->applied = TRUE;
4890 policy->pending_update = FALSE;
4891 return TRUE;
4892
4893 fail:
4894 return FALSE;
4895 }
4896
4897 static void
necp_policy_apply_all(struct necp_session * session)4898 necp_policy_apply_all(struct necp_session *session)
4899 {
4900 struct necp_session_policy *policy = NULL;
4901 struct necp_session_policy *temp_policy = NULL;
4902 struct kev_necp_policies_changed_data kev_data;
4903 kev_data.changed_count = 0;
4904
4905 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4906
4907 // Remove exisiting applied policies
4908 if (session->dirty) {
4909 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4910 if (policy->pending_deletion) {
4911 if (policy->applied) {
4912 necp_policy_unapply(policy);
4913 }
4914 // Delete the policy
4915 necp_policy_delete(session, policy);
4916 } else if (!policy->applied) {
4917 necp_policy_apply(session, policy);
4918 } else if (policy->pending_update) {
4919 // Must have been applied, but needs an update. Remove and re-add.
4920 necp_policy_unapply(policy);
4921 necp_policy_apply(session, policy);
4922 }
4923 }
4924
4925 necp_kernel_socket_policies_update_uuid_table();
4926 necp_kernel_socket_policies_reprocess();
4927 necp_kernel_ip_output_policies_reprocess();
4928
4929 // Clear dirty bit flags
4930 session->dirty = FALSE;
4931 }
4932
4933 lck_rw_done(&necp_kernel_policy_lock);
4934
4935 necp_update_all_clients();
4936 necp_post_change_event(&kev_data);
4937
4938 if (necp_debug) {
4939 NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4940 }
4941 }
4942
4943 // Kernel Policy Management
4944 // ---------------------
4945 // Kernel policies are derived from session policies
4946 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4947 necp_kernel_policy_get_new_id(bool socket_level)
4948 {
4949 static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4950 static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4951
4952 necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4953
4954 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4955
4956 if (socket_level) {
4957 bool wrapped = FALSE;
4958 do {
4959 necp_last_kernel_socket_policy_id++;
4960 if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4961 necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4962 if (wrapped) {
4963 // Already wrapped, give up
4964 NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4965 return NECP_KERNEL_POLICY_ID_NONE;
4966 }
4967 necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4968 wrapped = TRUE;
4969 }
4970 newid = necp_last_kernel_socket_policy_id;
4971 } while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4972 } else {
4973 bool wrapped = FALSE;
4974 do {
4975 necp_last_kernel_ip_policy_id++;
4976 if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4977 if (wrapped) {
4978 // Already wrapped, give up
4979 NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4980 return NECP_KERNEL_POLICY_ID_NONE;
4981 }
4982 necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4983 wrapped = TRUE;
4984 }
4985 newid = necp_last_kernel_ip_policy_id;
4986 } while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4987 }
4988
4989 if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4990 NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4991 return NECP_KERNEL_POLICY_ID_NONE;
4992 }
4993
4994 return newid;
4995 }
4996
4997 #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)
4998
4999 static necp_kernel_policy_id
necp_kernel_socket_policy_add(necp_policy_order order,u_int32_t session_order,int session_pid,u_int64_t condition_mask,u_int64_t condition_negated_mask,necp_app_id cond_app_id,necp_app_id cond_real_app_id,char * cond_custom_entitlement __null_terminated,u_int32_t cond_account_id,char * cond_domain __null_terminated,u_int32_t cond_domain_filter,char * cond_url __null_terminated,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 * __single 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 __null_terminated,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,u_int8_t cond_local_networks_flags,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)5000 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 __null_terminated, u_int32_t cond_account_id, char *cond_domain __null_terminated, u_int32_t cond_domain_filter, char *cond_url __null_terminated, 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 * __single 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 __null_terminated, 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, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
5001 {
5002 struct necp_kernel_socket_policy *new_kernel_policy = NULL;
5003 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5004
5005 new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
5006
5007 new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
5008 new_kernel_policy->order = order;
5009 new_kernel_policy->session_order = session_order;
5010 new_kernel_policy->session_pid = session_pid;
5011
5012 // Sanitize condition mask
5013 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
5014 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
5015 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
5016 }
5017 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
5018 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
5019 }
5020 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
5021 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
5022 }
5023 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
5024 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
5025 }
5026 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
5027 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
5028 }
5029 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
5030 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
5031 }
5032 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
5033 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
5034 }
5035 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
5036
5037 // Set condition values
5038 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
5039 new_kernel_policy->cond_app_id = cond_app_id;
5040 }
5041 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
5042 new_kernel_policy->cond_real_app_id = cond_real_app_id;
5043 }
5044 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
5045 new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
5046 }
5047 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
5048 new_kernel_policy->cond_account_id = cond_account_id;
5049 }
5050 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
5051 (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
5052 new_kernel_policy->cond_domain = cond_domain;
5053 new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
5054 }
5055 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
5056 new_kernel_policy->cond_domain_filter = cond_domain_filter;
5057 }
5058 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
5059 new_kernel_policy->cond_url = cond_url;
5060 }
5061 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
5062 new_kernel_policy->cond_pid = cond_pid;
5063 new_kernel_policy->cond_pid_version = cond_pid_version;
5064 }
5065 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
5066 new_kernel_policy->cond_uid = cond_uid;
5067 }
5068 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
5069 new_kernel_policy->cond_real_uid = cond_real_uid;
5070 }
5071 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
5072 if (cond_bound_interface) {
5073 ifnet_reference(cond_bound_interface);
5074 }
5075 new_kernel_policy->cond_bound_interface = cond_bound_interface;
5076 }
5077 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
5078 new_kernel_policy->cond_traffic_class = cond_traffic_class;
5079 }
5080 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
5081 new_kernel_policy->cond_protocol = cond_protocol;
5082 }
5083 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5084 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
5085 }
5086 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5087 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
5088 }
5089 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5090 new_kernel_policy->cond_local_prefix = cond_local_prefix;
5091 }
5092 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5093 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
5094 }
5095 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5096 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
5097 }
5098 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5099 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
5100 }
5101 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
5102 memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
5103 }
5104 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
5105 memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
5106 }
5107 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
5108 new_kernel_policy->cond_client_flags = cond_client_flags;
5109 }
5110 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
5111 new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
5112 }
5113 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
5114 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
5115 }
5116 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
5117 new_kernel_policy->cond_scheme_port = cond_scheme_port;
5118 }
5119 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
5120 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
5121 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
5122 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
5123 }
5124 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
5125 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
5126 }
5127
5128 new_kernel_policy->result = result;
5129 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
5130
5131 if (necp_debug) {
5132 NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
5133 }
5134 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
5135
5136 return new_kernel_policy ? new_kernel_policy->id : 0;
5137 }
5138
5139 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)5140 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
5141 {
5142 struct necp_kernel_socket_policy *kernel_policy = NULL;
5143 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5144
5145 if (policy_id == 0) {
5146 return NULL;
5147 }
5148
5149 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
5150 if (kernel_policy->id == policy_id) {
5151 return kernel_policy;
5152 }
5153 }
5154
5155 return NULL;
5156 }
5157
5158 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)5159 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
5160 {
5161 struct necp_kernel_socket_policy * __single policy = NULL;
5162 char * __indexable buffer = NULL;
5163 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5164
5165 policy = necp_kernel_socket_policy_find(policy_id);
5166 if (policy) {
5167 LIST_REMOVE(policy, chain);
5168
5169 if (policy->cond_bound_interface) {
5170 ifnet_release(policy->cond_bound_interface);
5171 policy->cond_bound_interface = NULL;
5172 }
5173
5174 if (policy->cond_domain) {
5175 buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
5176 kfree_data_addr(buffer);
5177 policy->cond_domain = NULL;
5178 }
5179
5180 if (policy->cond_url) {
5181 buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
5182 kfree_data_addr(buffer);
5183 policy->cond_url = NULL;
5184 }
5185
5186 if (policy->cond_custom_entitlement) {
5187 buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
5188 kfree_data_addr(buffer);
5189 policy->cond_custom_entitlement = NULL;
5190 }
5191
5192 if (policy->cond_signing_identifier) {
5193 buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
5194 kfree_data_addr(buffer);
5195 policy->cond_signing_identifier = NULL;
5196 }
5197
5198 zfree(necp_socket_policy_zone, policy);
5199 return TRUE;
5200 }
5201
5202 return FALSE;
5203 }
5204
5205 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)5206 __sized_by(MAX_RESULT_STRING_LEN)
5207 necp_get_result_description(char * __sized_by(MAX_RESULT_STRING_LEN) result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
5208 {
5209 uuid_string_t uuid_string;
5210 switch (result) {
5211 case NECP_KERNEL_POLICY_RESULT_NONE: {
5212 snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
5213 break;
5214 }
5215 case NECP_KERNEL_POLICY_RESULT_PASS: {
5216 snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
5217 break;
5218 }
5219 case NECP_KERNEL_POLICY_RESULT_SKIP: {
5220 snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
5221 break;
5222 }
5223 case NECP_KERNEL_POLICY_RESULT_DROP: {
5224 snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5225 break;
5226 }
5227 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5228 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5229 break;
5230 }
5231 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5232 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5233 break;
5234 }
5235 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5236 ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5237 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5238 break;
5239 }
5240 case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5241 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5242 break;
5243 }
5244 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5245 ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5246 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5247 break;
5248 }
5249 case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5250 snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5251 break;
5252 }
5253 case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5254 snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5255 break;
5256 }
5257 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5258 int index = 0;
5259 char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5260 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5261 if (route_rule != NULL) {
5262 for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5263 if (route_rule->exception_if_indices[index] != 0) {
5264 ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5265 snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5266 } else {
5267 memset(interface_names[index], 0, IFXNAMSIZ);
5268 }
5269 }
5270 switch (route_rule->default_action) {
5271 case NECP_ROUTE_RULE_DENY_INTERFACE:
5272 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5273 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%s)",
5274 (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5275 (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5276 (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5277 (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5278 (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5279 (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5280 (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5281 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5282 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5283 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5284 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5285 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5286 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5287 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5288 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5289 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5290 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5291 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5292 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5293 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5294 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5295 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5296 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5297 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5298 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5299 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5300 break;
5301 case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5302 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%s)",
5303 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5304 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5305 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5306 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5307 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5308 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5309 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5310 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5311 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5312 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5313 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5314 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5315 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5316 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5317 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5318 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5319 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5320 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5321 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5322 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5323 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5324 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5325 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5326 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5327 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5328 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5329 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5330 break;
5331 case NECP_ROUTE_RULE_QOS_MARKING:
5332 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%s)",
5333 (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5334 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5335 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5336 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5337 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5338 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5339 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5340 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5341 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5342 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5343 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5344 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5345 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5346 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5347 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5348 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5349 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5350 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5351 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5352 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5353 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5354 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5355 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5356 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5357 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5358 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5359 break;
5360 default:
5361 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5362 break;
5363 }
5364 }
5365 break;
5366 }
5367 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5368 bool found_mapping = FALSE;
5369 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5370 if (mapping != NULL) {
5371 uuid_unparse(mapping->uuid, uuid_string);
5372 found_mapping = TRUE;
5373 }
5374 snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5375 break;
5376 }
5377 case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5378 bool found_mapping = FALSE;
5379 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5380 if (mapping != NULL) {
5381 uuid_unparse(mapping->uuid, uuid_string);
5382 found_mapping = TRUE;
5383 }
5384 snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5385 break;
5386 }
5387 case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5388 bool found_mapping = FALSE;
5389 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5390 if (mapping != NULL) {
5391 uuid_unparse(mapping->uuid, uuid_string);
5392 found_mapping = TRUE;
5393 }
5394 snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5395 break;
5396 }
5397 default: {
5398 snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5399 break;
5400 }
5401 }
5402 return result_string;
5403 }
5404
5405 static void
necp_kernel_socket_policies_dump_all(void)5406 necp_kernel_socket_policies_dump_all(void)
5407 {
5408 if (necp_debug) {
5409 struct necp_kernel_socket_policy *policy = NULL;
5410 int policy_i;
5411 int app_i;
5412 char result_string[MAX_RESULT_STRING_LEN];
5413 char proc_name_string[MAXCOMLEN + 1];
5414 memset(result_string, 0, MAX_RESULT_STRING_LEN);
5415 memset(proc_name_string, 0, MAXCOMLEN + 1);
5416
5417 NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5418 NECPLOG0(LOG_DEBUG, "-----------\n");
5419 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5420 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5421 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5422 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));
5423 }
5424 if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5425 NECPLOG0(LOG_DEBUG, "-----------\n");
5426 }
5427
5428 NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5429 NECPLOG0(LOG_DEBUG, "-----------\n");
5430 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5431 NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5432 for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5433 policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5434 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5435 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));
5436 }
5437 NECPLOG0(LOG_DEBUG, "-----------\n");
5438 }
5439 }
5440 }
5441
5442 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5443 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5444 {
5445 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5446 // Drop always cancels out lower policies
5447 return TRUE;
5448 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5449 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5450 upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5451 upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5452 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5453 upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
5454 // Filters and route rules never cancel out lower policies
5455 return FALSE;
5456 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5457 if (upper_policy->session_order != lower_policy->session_order) {
5458 // A skip cannot override a policy of a different session
5459 return FALSE;
5460 } else {
5461 if (upper_policy->result_parameter.skip_policy_order == 0 ||
5462 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5463 // This policy is beyond the skip
5464 return FALSE;
5465 } else {
5466 // This policy is inside the skip
5467 return TRUE;
5468 }
5469 }
5470 }
5471
5472 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5473 return TRUE;
5474 }
5475
5476 static bool
necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy * policy,struct necp_kernel_socket_policy ** __indexable policy_array,int valid_indices)5477 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5478 {
5479 bool can_skip = FALSE;
5480 u_int32_t highest_skip_session_order = 0;
5481 u_int32_t highest_skip_order = 0;
5482 int i;
5483 for (i = 0; i < valid_indices; i++) {
5484 struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5485
5486 // For policies in a skip window, we can't mark conflicting policies as unnecessary
5487 if (can_skip) {
5488 if (highest_skip_session_order != compared_policy->session_order ||
5489 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5490 // If we've moved on to the next session, or passed the skip window
5491 highest_skip_session_order = 0;
5492 highest_skip_order = 0;
5493 can_skip = FALSE;
5494 } else {
5495 // If this policy is also a skip, in can increase the skip window
5496 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5497 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5498 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5499 }
5500 }
5501 continue;
5502 }
5503 }
5504
5505 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5506 // This policy is a skip. Set the skip window accordingly
5507 can_skip = TRUE;
5508 highest_skip_session_order = compared_policy->session_order;
5509 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5510 }
5511
5512 // The result of the compared policy must be able to block out this policy result
5513 if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5514 continue;
5515 }
5516
5517 // If new policy matches All Interfaces, compared policy must also
5518 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5519 continue;
5520 }
5521
5522 // If new policy matches Local Networks, compared policy must also
5523 if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5524 policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5525 continue;
5526 }
5527
5528 // Default makes lower policies unecessary always
5529 if (compared_policy->condition_mask == 0) {
5530 return TRUE;
5531 }
5532
5533 // Compared must be more general than policy, and include only conditions within policy
5534 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5535 continue;
5536 }
5537
5538 // Negative conditions must match for the overlapping conditions
5539 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5540 continue;
5541 }
5542
5543 if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5544 compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5545 strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5546 continue;
5547 }
5548
5549 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5550 compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5551 continue;
5552 }
5553
5554 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5555 strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5556 continue;
5557 }
5558
5559 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5560 strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5561 continue;
5562 }
5563
5564 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5565 compared_policy->cond_account_id != policy->cond_account_id) {
5566 continue;
5567 }
5568
5569 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5570 compared_policy->cond_policy_id != policy->cond_policy_id) {
5571 continue;
5572 }
5573
5574 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5575 compared_policy->cond_app_id != policy->cond_app_id) {
5576 continue;
5577 }
5578
5579 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5580 compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5581 continue;
5582 }
5583
5584 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5585 (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5586 continue;
5587 }
5588
5589 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5590 compared_policy->cond_uid != policy->cond_uid) {
5591 continue;
5592 }
5593
5594 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5595 compared_policy->cond_real_uid != policy->cond_real_uid) {
5596 continue;
5597 }
5598
5599 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5600 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5601 continue;
5602 }
5603
5604 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5605 compared_policy->cond_protocol != policy->cond_protocol) {
5606 continue;
5607 }
5608
5609 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5610 compared_policy->cond_client_flags != policy->cond_client_flags) {
5611 continue;
5612 }
5613
5614 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5615 !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5616 compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5617 continue;
5618 }
5619
5620 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5621 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5622 if (!necp_is_range_in_range(SA(&policy->cond_local_start), SA(&policy->cond_local_end), SA(&compared_policy->cond_local_start), SA(&compared_policy->cond_local_end))) {
5623 continue;
5624 }
5625 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5626 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5627 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5628 continue;
5629 }
5630 }
5631 }
5632
5633 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5634 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5635 if (!necp_is_range_in_range(SA(&policy->cond_remote_start), SA(&policy->cond_remote_end), SA(&compared_policy->cond_remote_start), SA(&compared_policy->cond_remote_end))) {
5636 continue;
5637 }
5638 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5639 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5640 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5641 continue;
5642 }
5643 }
5644 }
5645
5646 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5647 memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5648 continue;
5649 }
5650
5651 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5652 memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5653 continue;
5654 }
5655
5656 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5657 memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5658 continue;
5659 }
5660
5661 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5662 memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5663 continue;
5664 }
5665
5666 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5667 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5668 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5669 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5670 continue;
5671 }
5672
5673 return TRUE;
5674 }
5675
5676 return FALSE;
5677 }
5678
5679 static bool
necp_kernel_socket_policies_reprocess(void)5680 necp_kernel_socket_policies_reprocess(void)
5681 {
5682 int app_i;
5683 int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5684 int app_layer_current_free_index = 0;
5685 struct necp_kernel_socket_policy *kernel_policy = NULL;
5686
5687 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5688
5689 // Reset mask to 0
5690 necp_kernel_application_policies_condition_mask = 0;
5691 necp_kernel_socket_policies_condition_mask = 0;
5692 necp_kernel_application_policies_count = 0;
5693 necp_kernel_socket_policies_count = 0;
5694 necp_kernel_socket_policies_non_app_count = 0;
5695
5696 // Reset all maps to NULL
5697 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5698 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5699 kfree_type(struct necp_kernel_socket_policy *,
5700 necp_kernel_socket_policies_map_counts[app_i] + 1,
5701 necp_kernel_socket_policies_map[app_i]);
5702 necp_kernel_socket_policies_map[app_i] = NULL;
5703 }
5704
5705 // Init counts
5706 necp_kernel_socket_policies_map_counts[app_i] = 0;
5707 }
5708 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5709 kfree_type(struct necp_kernel_socket_policy *,
5710 necp_kernel_socket_policies_app_layer_map_count + 1,
5711 necp_kernel_socket_policies_app_layer_map);
5712 }
5713 necp_kernel_socket_policies_app_layer_map = NULL;
5714 necp_kernel_socket_policies_app_layer_map_count = 0;
5715
5716 // Create masks and counts
5717 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5718 // App layer mask/count
5719 necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5720 necp_kernel_application_policies_count++;
5721 necp_kernel_socket_policies_app_layer_map_count++;
5722
5723 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5724 // Agent type conditions only apply to app layer
5725 continue;
5726 }
5727
5728 // Update socket layer bucket mask/counts
5729 necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5730 necp_kernel_socket_policies_count++;
5731
5732 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5733 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5734 necp_kernel_socket_policies_non_app_count++;
5735 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5736 necp_kernel_socket_policies_map_counts[app_i]++;
5737 }
5738 } else {
5739 necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5740 }
5741 }
5742
5743 // Allocate maps
5744 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5745 if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5746 // Allocate a NULL-terminated array of policy pointers for each bucket
5747 necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5748 necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5749 if (necp_kernel_socket_policies_map[app_i] == NULL) {
5750 goto fail;
5751 }
5752 }
5753 bucket_current_free_index[app_i] = 0;
5754 }
5755 necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5756 necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5757 if (necp_kernel_socket_policies_app_layer_map == NULL) {
5758 goto fail;
5759 }
5760
5761 // Fill out maps
5762 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5763 // Add app layer policies
5764 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5765 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5766 app_layer_current_free_index++;
5767 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5768 }
5769
5770 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5771 // Agent type conditions only apply to app layer
5772 continue;
5773 }
5774
5775 // Add socket policies
5776 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5777 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5778 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5779 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_map[app_i], bucket_current_free_index[app_i])) {
5780 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5781 bucket_current_free_index[app_i]++;
5782 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5783 }
5784 }
5785 } else {
5786 app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5787 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_map[app_i], bucket_current_free_index[app_i])) {
5788 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5789 bucket_current_free_index[app_i]++;
5790 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5791 }
5792 }
5793 }
5794 necp_kernel_socket_policies_dump_all();
5795 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5796 return TRUE;
5797
5798 fail:
5799 // Free memory, reset masks to 0
5800 necp_kernel_application_policies_condition_mask = 0;
5801 necp_kernel_socket_policies_condition_mask = 0;
5802 necp_kernel_application_policies_count = 0;
5803 necp_kernel_socket_policies_count = 0;
5804 necp_kernel_socket_policies_non_app_count = 0;
5805 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5806 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5807 kfree_type(struct necp_kernel_socket_policy *,
5808 necp_kernel_socket_policies_map_counts[app_i] + 1,
5809 necp_kernel_socket_policies_map[app_i]);
5810 necp_kernel_socket_policies_map[app_i] = NULL;
5811 }
5812 necp_kernel_socket_policies_map_counts[app_i] = 0;
5813 }
5814 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5815 kfree_type(struct necp_kernel_socket_policy *,
5816 necp_kernel_socket_policies_app_layer_map_count + 1,
5817 necp_kernel_socket_policies_app_layer_map);
5818 necp_kernel_socket_policies_app_layer_map = NULL;
5819 }
5820 necp_kernel_socket_policies_app_layer_map_count = 0;
5821 return FALSE;
5822 }
5823
5824 static u_int32_t
necp_get_new_string_id(void)5825 necp_get_new_string_id(void)
5826 {
5827 static u_int32_t necp_last_string_id = 0;
5828
5829 u_int32_t newid = 0;
5830
5831 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5832
5833 bool wrapped = FALSE;
5834 do {
5835 necp_last_string_id++;
5836 if (necp_last_string_id < 1) {
5837 if (wrapped) {
5838 // Already wrapped, give up
5839 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5840 return 0;
5841 }
5842 necp_last_string_id = 1;
5843 wrapped = TRUE;
5844 }
5845 newid = necp_last_string_id;
5846 } while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5847
5848 if (newid == 0) {
5849 NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5850 return 0;
5851 }
5852
5853 return newid;
5854 }
5855
5856 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5857 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5858 {
5859 struct necp_string_id_mapping *searchentry = NULL;
5860 struct necp_string_id_mapping *foundentry = NULL;
5861
5862 LIST_FOREACH(searchentry, list, chain) {
5863 if (strcmp(searchentry->string, string) == 0) {
5864 foundentry = searchentry;
5865 break;
5866 }
5867 }
5868
5869 return foundentry;
5870 }
5871
5872 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5873 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5874 {
5875 struct necp_string_id_mapping *searchentry = NULL;
5876 struct necp_string_id_mapping *foundentry = NULL;
5877
5878 LIST_FOREACH(searchentry, list, chain) {
5879 if (searchentry->id == local_id) {
5880 foundentry = searchentry;
5881 break;
5882 }
5883 }
5884
5885 return foundentry;
5886 }
5887
5888 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5889 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5890 {
5891 u_int32_t string_id = 0;
5892 struct necp_string_id_mapping *existing_mapping = NULL;
5893
5894 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5895
5896 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5897 if (existing_mapping != NULL) {
5898 string_id = existing_mapping->id;
5899 os_ref_retain_locked(&existing_mapping->refcount);
5900 } else {
5901 struct necp_string_id_mapping * __single new_mapping = NULL;
5902 new_mapping = kalloc_type(struct necp_string_id_mapping,
5903 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5904
5905 size_t length = strlen(string) + 1;
5906 char *buffer = kalloc_data(length, Z_WAITOK);
5907 if (buffer != NULL) {
5908 strlcpy(buffer, string, length);
5909 new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5910 new_mapping->id = necp_get_new_string_id();
5911 os_ref_init(&new_mapping->refcount, &necp_refgrp);
5912 LIST_INSERT_HEAD(list, new_mapping, chain);
5913 string_id = new_mapping->id;
5914 } else {
5915 kfree_type(struct necp_string_id_mapping, new_mapping);
5916 new_mapping = NULL;
5917 }
5918 }
5919 return string_id;
5920 }
5921
5922 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5923 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5924 {
5925 struct necp_string_id_mapping * __single existing_mapping = NULL;
5926 char * __indexable buffer = NULL;
5927
5928 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5929
5930 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5931 if (existing_mapping != NULL) {
5932 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5933 LIST_REMOVE(existing_mapping, chain);
5934 buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5935 kfree_data_addr(buffer);
5936 kfree_type(struct necp_string_id_mapping, existing_mapping);
5937 }
5938 return TRUE;
5939 }
5940
5941 return FALSE;
5942 }
5943
5944 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5945 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5946 {
5947 struct necp_domain_filter *searchfilter = NULL;
5948 struct necp_domain_filter *foundfilter = NULL;
5949
5950 LIST_FOREACH(searchfilter, list, chain) {
5951 if (searchfilter->id == filter_id) {
5952 foundfilter = searchfilter;
5953 break;
5954 }
5955 }
5956
5957 return foundfilter;
5958 }
5959
5960 static u_int32_t
necp_get_new_domain_filter_id(void)5961 necp_get_new_domain_filter_id(void)
5962 {
5963 static u_int32_t necp_last_filter_id = 0;
5964
5965 u_int32_t newid = 0;
5966
5967 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5968
5969 bool wrapped = FALSE;
5970 do {
5971 // Scope id within its space
5972 if (++necp_last_filter_id > NECP_DOMAIN_FILTER_ID_MAX) {
5973 necp_last_filter_id = 0;
5974 }
5975 if (necp_last_filter_id < 1) {
5976 if (wrapped) {
5977 // Already wrapped, give up
5978 NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5979 return 0;
5980 }
5981 necp_last_filter_id = 1;
5982 wrapped = TRUE;
5983 }
5984 newid = necp_last_filter_id;
5985 } while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5986
5987 if (newid == 0) {
5988 NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5989 return 0;
5990 }
5991
5992 return newid;
5993 }
5994
5995 static u_int32_t
necp_create_domain_filter(struct necp_domain_filter_list * list,struct necp_domain_filter_list * owner_list,struct net_bloom_filter * filter)5996 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5997 {
5998 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5999
6000 struct necp_domain_filter *new_filter = NULL;
6001 new_filter = kalloc_type(struct necp_domain_filter,
6002 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6003
6004 new_filter->filter = filter;
6005 new_filter->id = necp_get_new_domain_filter_id();
6006 LIST_INSERT_HEAD(list, new_filter, chain);
6007 LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
6008 os_ref_init(&new_filter->refcount, &necp_refgrp);
6009
6010 return new_filter->id;
6011 }
6012
6013 static bool
necp_remove_domain_filter(struct necp_domain_filter_list * list,__unused struct necp_domain_filter_list * owner_list,u_int32_t filter_id)6014 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
6015 {
6016 struct necp_domain_filter * __single existing_filter = NULL;
6017
6018 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6019
6020 existing_filter = necp_lookup_domain_filter(list, filter_id);
6021 if (existing_filter != NULL) {
6022 if (os_ref_release_locked(&existing_filter->refcount) == 0) {
6023 LIST_REMOVE(existing_filter, chain);
6024 LIST_REMOVE(existing_filter, owner_chain);
6025 net_bloom_filter_destroy(existing_filter->filter);
6026 kfree_type(struct necp_domain_filter, existing_filter);
6027 }
6028 return true;
6029 }
6030
6031 return false;
6032 }
6033
6034 static struct necp_domain_trie *
necp_lookup_domain_trie(struct necp_domain_trie_list * list,u_int32_t id)6035 necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id)
6036 {
6037 struct necp_domain_trie *searchTrie = NULL;
6038 struct necp_domain_trie *foundTrie = NULL;
6039
6040 LIST_FOREACH(searchTrie, list, chain) {
6041 if (searchTrie->id == id) {
6042 foundTrie = searchTrie;
6043 break;
6044 }
6045 }
6046
6047 return foundTrie;
6048 }
6049
6050 static u_int32_t
necp_get_new_domain_trie_id(void)6051 necp_get_new_domain_trie_id(void)
6052 {
6053 static u_int32_t necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START;
6054 u_int32_t newid = necp_last_trie_id;
6055
6056 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6057
6058 bool wrapped = FALSE;
6059 do {
6060 if (++necp_last_trie_id < NECP_DOMAIN_TRIE_ID_START + 1) {
6061 if (wrapped) {
6062 // Already wrapped, give up
6063 NECPLOG0(LOG_ERR, "Failed to find a free trie ID.\n");
6064 return 0;
6065 }
6066 necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START + 1;
6067 wrapped = TRUE;
6068 }
6069 newid = necp_last_trie_id;
6070 } while (necp_lookup_domain_trie(&necp_global_domain_trie_list, newid) != NULL); // If already used, keep trying
6071
6072 if (newid == NECP_DOMAIN_TRIE_ID_START) {
6073 NECPLOG0(LOG_ERR, "Allocate trie id failed.\n");
6074 return 0;
6075 }
6076
6077 return newid;
6078 }
6079
6080 static u_int32_t
necp_create_domain_trie(struct necp_domain_trie_list * list,struct necp_domain_trie_list * owner_list,struct necp_domain_trie_request * trie_request,size_t trie_request_size)6081 necp_create_domain_trie(struct necp_domain_trie_list *list,
6082 struct necp_domain_trie_list *owner_list,
6083 struct necp_domain_trie_request *trie_request, size_t trie_request_size)
6084 {
6085 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6086
6087 struct necp_domain_trie *new_trie = NULL;
6088 new_trie = kalloc_type(struct necp_domain_trie, Z_WAITOK | Z_ZERO | Z_NOFAIL);
6089 if (new_trie == NULL) {
6090 NECPLOG0(LOG_ERR, "Failed to allow domain trie\n");
6091 return 0;
6092 }
6093
6094 if (net_trie_init_with_mem(&new_trie->trie, trie_request->data, trie_request->total_mem_size,
6095 trie_request->nodes_mem_size, trie_request->maps_mem_size, trie_request->bytes_mem_size,
6096 trie_request->nodes_count, trie_request->maps_count, trie_request->bytes_count) == false) {
6097 NECPLOG0(LOG_ERR, "Failed to initialize domain trie\n");
6098 kfree_type(struct necp_domain_trie, new_trie);
6099 return 0;
6100 }
6101 new_trie->trie_request = trie_request;
6102 new_trie->trie_request_size = trie_request_size;
6103 new_trie->id = necp_get_new_domain_trie_id();
6104 new_trie->trie_request->id = new_trie->id;
6105 LIST_INSERT_HEAD(list, new_trie, chain);
6106 LIST_INSERT_HEAD(owner_list, new_trie, owner_chain);
6107
6108 os_ref_init(&new_trie->refcount, &necp_refgrp);
6109 necp_trie_count++;
6110 return new_trie->id;
6111 }
6112
6113 static void
necp_free_domain_trie(struct necp_domain_trie * existing_trie)6114 necp_free_domain_trie(struct necp_domain_trie *existing_trie)
6115 {
6116 if (existing_trie != NULL) {
6117 uint8_t *necp_trie_request_buffer = (uint8_t *)existing_trie->trie_request;
6118 kfree_data(necp_trie_request_buffer, existing_trie->trie_request_size);
6119 kfree_type(struct necp_domain_trie, existing_trie);
6120 }
6121 }
6122
6123 static bool
necp_remove_domain_trie(struct necp_domain_trie_list * list,__unused struct necp_domain_trie_list * owner_list,u_int32_t id)6124 necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id)
6125 {
6126 struct necp_domain_trie * __single existing_trie = NULL;
6127
6128 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6129
6130 existing_trie = necp_lookup_domain_trie(list, id);
6131 if (existing_trie != NULL) {
6132 if (os_ref_release_locked(&existing_trie->refcount) == 0) {
6133 LIST_REMOVE(existing_trie, chain);
6134 LIST_REMOVE(existing_trie, owner_chain);
6135 necp_free_domain_trie(existing_trie);
6136 necp_trie_count--;
6137 }
6138 return true;
6139 }
6140
6141 return false;
6142 }
6143
6144 static Boolean
necp_match_domain_with_trie(struct necp_domain_trie_list * list,u_int32_t id,char * __sized_by (length)domain,size_t length)6145 necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length)
6146 {
6147 size_t metadata_length = 0;
6148 const uint8_t * __sized_by(metadata_length) metadata = NULL;
6149
6150 struct necp_domain_trie *necp_trie = necp_lookup_domain_trie(list, id);
6151 if (necp_trie == NULL || necp_trie->trie_request == NULL) {
6152 return false;
6153 }
6154 Boolean reverse = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_REVERSE_SEARCH);
6155 Boolean allow_partial_match = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_ALLOW_PARTIAL_MATCH);
6156 return net_trie_search(&necp_trie->trie, (const uint8_t *)domain, length,
6157 &metadata, &metadata_length, reverse, allow_partial_match, necp_trie->trie_request->partial_match_terminator, NULL, NULL) != NULL_TRIE_IDX;
6158 }
6159
6160 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
6161 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
6162 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)6163 necp_get_new_route_rule_id(bool aggregate)
6164 {
6165 static u_int32_t necp_last_route_rule_id = 0;
6166 static u_int32_t necp_last_aggregate_route_rule_id = 0;
6167
6168 u_int32_t newid = 0;
6169
6170 if (!aggregate) {
6171 // Main necp_kernel_policy_lock protects non-aggregate rule IDs
6172 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6173
6174 bool wrapped = FALSE;
6175 do {
6176 necp_last_route_rule_id++;
6177 if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
6178 necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6179 if (wrapped) {
6180 // Already wrapped, give up
6181 NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
6182 return 0;
6183 }
6184 necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
6185 wrapped = TRUE;
6186 }
6187 newid = necp_last_route_rule_id;
6188 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6189 } else {
6190 // necp_route_rule_lock protects aggregate rule IDs
6191 LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
6192
6193 bool wrapped = FALSE;
6194 do {
6195 necp_last_aggregate_route_rule_id++;
6196 if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6197 if (wrapped) {
6198 // Already wrapped, give up
6199 NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
6200 return 0;
6201 }
6202 necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
6203 wrapped = TRUE;
6204 }
6205 newid = necp_last_aggregate_route_rule_id;
6206 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6207 }
6208
6209 if (newid == 0) {
6210 NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
6211 return 0;
6212 }
6213
6214 return newid;
6215 }
6216
6217 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)6218 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6219 {
6220 struct necp_route_rule *searchentry = NULL;
6221 struct necp_route_rule *foundentry = NULL;
6222
6223 LIST_FOREACH(searchentry, list, chain) {
6224 if (searchentry->id == route_rule_id) {
6225 foundentry = searchentry;
6226 break;
6227 }
6228 }
6229
6230 return foundentry;
6231 }
6232
6233 static struct necp_route_rule *
necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list * list,u_int8_t default_action,u_int8_t cellular_action,u_int8_t wifi_action,u_int8_t wired_action,u_int8_t expensive_action,u_int8_t constrained_action,u_int8_t companion_action,u_int8_t vpn_action,u_int32_t * __indexable if_indices,u_int8_t * __indexable if_actions,uuid_t netagent_uuid,uuid_t match_netagent_uuid,u_int32_t control_unit,u_int32_t effective_type)6234 necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list *list, u_int8_t default_action, u_int8_t cellular_action, u_int8_t wifi_action, u_int8_t wired_action, u_int8_t expensive_action, u_int8_t constrained_action, u_int8_t companion_action, u_int8_t vpn_action, u_int32_t * __indexable if_indices, u_int8_t * __indexable if_actions, uuid_t netagent_uuid, uuid_t match_netagent_uuid, u_int32_t control_unit, u_int32_t effective_type)
6235 {
6236 struct necp_route_rule *searchentry = NULL;
6237 struct necp_route_rule *foundentry = NULL;
6238
6239 LIST_FOREACH(searchentry, list, chain) {
6240 if (searchentry->default_action == default_action &&
6241 searchentry->cellular_action == cellular_action &&
6242 searchentry->wifi_action == wifi_action &&
6243 searchentry->wired_action == wired_action &&
6244 searchentry->expensive_action == expensive_action &&
6245 searchentry->constrained_action == constrained_action &&
6246 searchentry->companion_action == companion_action &&
6247 searchentry->vpn_action == vpn_action &&
6248 searchentry->control_unit == control_unit &&
6249 searchentry->effective_type == effective_type) {
6250 bool match_failed = FALSE;
6251 size_t index_a = 0;
6252 size_t index_b = 0;
6253 size_t count_a = 0;
6254 size_t count_b = 0;
6255 for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
6256 bool found_index = FALSE;
6257 if (searchentry->exception_if_indices[index_a] == 0) {
6258 break;
6259 }
6260 count_a++;
6261 for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
6262 if (if_indices[index_b] == 0) {
6263 break;
6264 }
6265 if (index_b >= count_b) {
6266 count_b = index_b + 1;
6267 }
6268 if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
6269 searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
6270 found_index = TRUE;
6271 break;
6272 }
6273 }
6274 if (!found_index) {
6275 match_failed = TRUE;
6276 break;
6277 }
6278 }
6279
6280 if (match_failed || count_a != count_b) {
6281 continue;
6282 }
6283
6284 bool has_agent_a = !uuid_is_null(netagent_uuid);
6285 bool has_agent_b = (searchentry->netagent_id != 0);
6286 if (has_agent_a != has_agent_b) {
6287 continue;
6288 }
6289
6290 if (has_agent_a) {
6291 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
6292 if (mapping == NULL) {
6293 // Bad mapping, doesn't match
6294 continue;
6295 }
6296 if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
6297 // UUIDs don't match
6298 continue;
6299 }
6300 }
6301
6302 bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
6303 bool has_match_agent_b = (searchentry->match_netagent_id != 0);
6304 if (has_match_agent_a != has_match_agent_b) {
6305 continue;
6306 }
6307
6308 if (has_match_agent_a) {
6309 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->match_netagent_id);
6310 if (mapping == NULL) {
6311 // Bad mapping, doesn't match
6312 continue;
6313 }
6314 if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
6315 // UUIDs don't match
6316 continue;
6317 }
6318 }
6319
6320 // Rules match!
6321 foundentry = searchentry;
6322 break;
6323 }
6324 }
6325
6326 return foundentry;
6327 }
6328
6329 static u_int32_t
necp_create_route_rule(struct necp_route_rule_list * list,u_int8_t * __sized_by (route_rules_array_size)route_rules_array,u_int32_t route_rules_array_size,bool * has_socket_only_actions)6330 necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size,
6331 bool *has_socket_only_actions)
6332 {
6333 size_t offset = 0;
6334 u_int32_t route_rule_id = 0;
6335 struct necp_route_rule *existing_rule = NULL;
6336 u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
6337 u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
6338 u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
6339 u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
6340 u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
6341 u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
6342 u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
6343 u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
6344 u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
6345 size_t num_valid_indices = 0;
6346 memset(&if_indices, 0, sizeof(if_indices));
6347 u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
6348 memset(&if_actions, 0, sizeof(if_actions));
6349
6350 uuid_t netagent_uuid = {};
6351
6352 uuid_t match_netagent_uuid = {};
6353 uint32_t control_unit = 0;
6354 uint32_t effective_type = 0;
6355
6356 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6357
6358 if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6359 return 0;
6360 }
6361
6362 // Process rules
6363 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6364 ifnet_t __single rule_interface = NULL;
6365 char interface_name[IFXNAMSIZ];
6366 u_int32_t length = 0;
6367 u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6368
6369 if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6370 // Invalid TLV goes beyond end of the rules array
6371 break;
6372 }
6373
6374 // Increment offset for the next time through the loop
6375 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6376
6377 u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6378 u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6379 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6380 u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6381
6382 if (rule_action == NECP_ROUTE_RULE_NONE) {
6383 // Don't allow an explicit rule to be None action
6384 continue;
6385 }
6386
6387 if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6388 rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6389 if (rule_length < sizeof(uuid_t)) {
6390 // Too short, skip
6391 continue;
6392 }
6393
6394 if (!uuid_is_null(netagent_uuid)) {
6395 if (uuid_compare(netagent_uuid, rule_value) != 0) {
6396 // UUIDs don't match, skip
6397 continue;
6398 }
6399 } else {
6400 // Copy out agent UUID
6401 memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6402 }
6403
6404 // Adjust remaining length
6405 rule_value += sizeof(netagent_uuid);
6406 rule_length -= sizeof(netagent_uuid);
6407 *has_socket_only_actions = true;
6408 } else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6409 if (rule_length < sizeof(control_unit)) {
6410 // Too short, skip
6411 continue;
6412 }
6413
6414 memcpy(&control_unit, rule_value, sizeof(control_unit));
6415
6416 // Adjust remaining length
6417 rule_value += sizeof(control_unit);
6418 rule_length -= sizeof(control_unit);
6419 *has_socket_only_actions = true;
6420 } else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6421 if (rule_length < sizeof(effective_type)) {
6422 // Too short, skip
6423 continue;
6424 }
6425
6426 memcpy(&effective_type, rule_value, sizeof(effective_type));
6427
6428 // Adjust remaining length
6429 rule_value += sizeof(effective_type);
6430 rule_length -= sizeof(effective_type);
6431 }
6432
6433 if (rule_length == 0) {
6434 if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6435 cellular_action = rule_action;
6436 }
6437 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6438 wifi_action = rule_action;
6439 }
6440 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6441 wired_action = rule_action;
6442 }
6443 if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6444 expensive_action = rule_action;
6445 }
6446 if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6447 constrained_action = rule_action;
6448 }
6449 if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6450 companion_action = rule_action;
6451 }
6452 if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6453 vpn_action = rule_action;
6454 }
6455 if (rule_flags == 0) {
6456 default_action = rule_action;
6457 }
6458 continue;
6459 } else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6460 if (rule_length < sizeof(uuid_t)) {
6461 // Too short, skip
6462 continue;
6463 }
6464
6465 // Store the netagent UUID to match
6466 memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6467 // If the data is exactly a UUID, this is the default action
6468 if (rule_length == sizeof(uuid_t)) {
6469 default_action = rule_action;
6470 continue;
6471 }
6472
6473 // If the data is longer than a UUID, this also includes an interface name
6474 // Adjust remaining length to make sure the interface name is picked up below
6475 rule_value += sizeof(uuid_t);
6476 rule_length -= sizeof(uuid_t);
6477 }
6478
6479 if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6480 continue;
6481 }
6482
6483 if (rule_length <= IFXNAMSIZ) {
6484 memcpy(interface_name, rule_value, rule_length);
6485 interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6486 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6487 if_actions[num_valid_indices] = rule_action;
6488 if_indices[num_valid_indices++] = rule_interface->if_index;
6489 ifnet_release(rule_interface);
6490 }
6491 }
6492 }
6493
6494 existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, companion_action, vpn_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit, effective_type);
6495 if (existing_rule != NULL) {
6496 route_rule_id = existing_rule->id;
6497 os_ref_retain_locked(&existing_rule->refcount);
6498 } else {
6499 struct necp_route_rule *new_rule = NULL;
6500 new_rule = kalloc_type(struct necp_route_rule,
6501 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6502 route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6503 if (!uuid_is_null(netagent_uuid)) {
6504 new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
6505 }
6506 if (!uuid_is_null(match_netagent_uuid)) {
6507 new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(match_netagent_uuid);
6508 }
6509 new_rule->effective_type = effective_type;
6510 new_rule->control_unit = control_unit;
6511 new_rule->default_action = default_action;
6512 new_rule->cellular_action = cellular_action;
6513 new_rule->wifi_action = wifi_action;
6514 new_rule->wired_action = wired_action;
6515 new_rule->expensive_action = expensive_action;
6516 new_rule->constrained_action = constrained_action;
6517 new_rule->companion_action = companion_action;
6518 new_rule->vpn_action = vpn_action;
6519 memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6520 memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6521 os_ref_init(&new_rule->refcount, &necp_refgrp);
6522 LIST_INSERT_HEAD(list, new_rule, chain);
6523 }
6524 return route_rule_id;
6525 }
6526
6527 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6528 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6529 {
6530 if (rule_id) {
6531 lck_rw_lock_exclusive(&necp_route_rule_lock);
6532
6533 struct necp_aggregate_route_rule * __single existing_rule = NULL;
6534 struct necp_aggregate_route_rule *tmp_rule = NULL;
6535
6536 LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6537 int index = 0;
6538 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6539 u_int32_t route_rule_id = existing_rule->rule_ids[index];
6540 if (route_rule_id == rule_id) {
6541 LIST_REMOVE(existing_rule, chain);
6542 kfree_type(struct necp_aggregate_route_rule, existing_rule);
6543 break;
6544 }
6545 }
6546 }
6547
6548 lck_rw_done(&necp_route_rule_lock);
6549 }
6550 }
6551
6552 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6553 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6554 {
6555 struct necp_route_rule * __single existing_rule = NULL;
6556
6557 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6558
6559 existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6560 if (existing_rule != NULL) {
6561 if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6562 necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6563 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
6564 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->match_netagent_id);
6565 LIST_REMOVE(existing_rule, chain);
6566 kfree_type(struct necp_route_rule, existing_rule);
6567 }
6568 return TRUE;
6569 }
6570
6571 return FALSE;
6572 }
6573
6574 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6575 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6576 {
6577 struct necp_aggregate_route_rule *searchentry = NULL;
6578 struct necp_aggregate_route_rule *foundentry = NULL;
6579
6580 lck_rw_lock_shared(&necp_route_rule_lock);
6581
6582 LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6583 if (searchentry->id == route_rule_id) {
6584 foundentry = searchentry;
6585 break;
6586 }
6587 }
6588
6589 lck_rw_done(&necp_route_rule_lock);
6590
6591 return foundentry;
6592 }
6593
6594 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6595 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6596 {
6597 u_int32_t aggregate_route_rule_id = 0;
6598 struct necp_aggregate_route_rule *new_rule = NULL;
6599 struct necp_aggregate_route_rule *existing_rule = NULL;
6600
6601 lck_rw_lock_exclusive(&necp_route_rule_lock);
6602
6603 // Check if the rule already exists
6604 LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6605 if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6606 lck_rw_done(&necp_route_rule_lock);
6607 return existing_rule->id;
6608 }
6609 }
6610
6611 new_rule = kalloc_type(struct necp_aggregate_route_rule,
6612 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6613 aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6614 new_rule->id = aggregate_route_rule_id;
6615 memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6616 LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6617 lck_rw_done(&necp_route_rule_lock);
6618
6619 return aggregate_route_rule_id;
6620 }
6621
6622 #define NECP_NULL_SERVICE_ID 1
6623 #define NECP_FIRST_VALID_SERVICE_ID 2
6624 #define NECP_FIRST_VALID_APP_ID UINT16_MAX
6625 static u_int32_t
necp_get_new_uuid_id(bool service)6626 necp_get_new_uuid_id(bool service)
6627 {
6628 static u_int32_t necp_last_service_uuid_id = 0;
6629 static u_int32_t necp_last_app_uuid_id = 0;
6630
6631 u_int32_t newid = 0;
6632
6633 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6634
6635 if (service) {
6636 bool wrapped = FALSE;
6637 do {
6638 necp_last_service_uuid_id++;
6639 if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
6640 necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
6641 if (wrapped) {
6642 // Already wrapped, give up
6643 NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
6644 return NECP_NULL_SERVICE_ID;
6645 }
6646 necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
6647 wrapped = TRUE;
6648 }
6649 newid = necp_last_service_uuid_id;
6650 } while (necp_uuid_lookup_uuid_with_service_id_locked(newid) != NULL); // If already used, keep trying
6651 } else {
6652 bool wrapped = FALSE;
6653 do {
6654 necp_last_app_uuid_id++;
6655 if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
6656 if (wrapped) {
6657 // Already wrapped, give up
6658 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
6659 return NECP_NULL_SERVICE_ID;
6660 }
6661 necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
6662 wrapped = TRUE;
6663 }
6664 newid = necp_last_app_uuid_id;
6665 } while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6666 }
6667
6668 if (newid == NECP_NULL_SERVICE_ID) {
6669 NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
6670 return NECP_NULL_SERVICE_ID;
6671 }
6672
6673 return newid;
6674 }
6675
6676 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6677 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6678 {
6679 struct necp_uuid_id_mapping *searchentry = NULL;
6680 struct necp_uuid_id_mapping *foundentry = NULL;
6681
6682 LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6683 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6684 foundentry = searchentry;
6685 break;
6686 }
6687 }
6688
6689 return foundentry;
6690 }
6691
6692 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6693 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6694 {
6695 struct necp_uuid_id_mapping *searchentry = NULL;
6696 struct necp_uuid_id_mapping *foundentry = NULL;
6697
6698 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6699 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--) {
6700 LIST_FOREACH(searchentry, uuid_list_head, chain) {
6701 if (searchentry->id == local_id) {
6702 foundentry = searchentry;
6703 break;
6704 }
6705 }
6706 }
6707
6708 return foundentry;
6709 }
6710
6711 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6712 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6713 {
6714 u_int32_t local_id = 0;
6715 struct necp_uuid_id_mapping *existing_mapping = NULL;
6716
6717 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6718
6719 if (allocated_mapping) {
6720 *allocated_mapping = FALSE;
6721 }
6722
6723 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6724 if (existing_mapping != NULL) {
6725 local_id = existing_mapping->id;
6726 os_ref_retain_locked(&existing_mapping->refcount);
6727 if (uuid_policy_table) {
6728 existing_mapping->table_usecount++;
6729 }
6730 } else {
6731 struct necp_uuid_id_mapping *new_mapping = NULL;
6732 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6733 Z_WAITOK | Z_NOFAIL);
6734 uuid_copy(new_mapping->uuid, uuid);
6735 new_mapping->id = necp_get_new_uuid_id(false);
6736 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6737 if (uuid_policy_table) {
6738 new_mapping->table_usecount = 1;
6739 } else {
6740 new_mapping->table_usecount = 0;
6741 }
6742
6743 LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6744
6745 if (allocated_mapping) {
6746 *allocated_mapping = TRUE;
6747 }
6748
6749 local_id = new_mapping->id;
6750 }
6751
6752 return local_id;
6753 }
6754
6755 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6756 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6757 {
6758 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6759
6760 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6761
6762 if (removed_mapping) {
6763 *removed_mapping = FALSE;
6764 }
6765
6766 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6767 if (existing_mapping != NULL) {
6768 if (uuid_policy_table) {
6769 existing_mapping->table_usecount--;
6770 }
6771 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6772 LIST_REMOVE(existing_mapping, chain);
6773 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6774 if (removed_mapping) {
6775 *removed_mapping = TRUE;
6776 }
6777 }
6778 return TRUE;
6779 }
6780
6781 return FALSE;
6782 }
6783
6784 static struct necp_uuid_id_mapping *
necp_uuid_get_null_service_id_mapping(void)6785 necp_uuid_get_null_service_id_mapping(void)
6786 {
6787 static struct necp_uuid_id_mapping null_mapping;
6788 uuid_clear(null_mapping.uuid);
6789 null_mapping.id = NECP_NULL_SERVICE_ID;
6790
6791 return &null_mapping;
6792 }
6793
6794 static struct necp_uuid_id_mapping *
necp_uuid_lookup_service_id_locked(uuid_t uuid)6795 necp_uuid_lookup_service_id_locked(uuid_t uuid)
6796 {
6797 struct necp_uuid_id_mapping *searchentry = NULL;
6798 struct necp_uuid_id_mapping *foundentry = NULL;
6799
6800 if (uuid_is_null(uuid)) {
6801 return necp_uuid_get_null_service_id_mapping();
6802 }
6803
6804 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6805 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6806 foundentry = searchentry;
6807 break;
6808 }
6809 }
6810
6811 return foundentry;
6812 }
6813
6814 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)6815 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
6816 {
6817 struct necp_uuid_id_mapping *searchentry = NULL;
6818 struct necp_uuid_id_mapping *foundentry = NULL;
6819
6820 if (local_id == NECP_NULL_SERVICE_ID) {
6821 return necp_uuid_get_null_service_id_mapping();
6822 }
6823
6824 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6825 if (searchentry->id == local_id) {
6826 foundentry = searchentry;
6827 break;
6828 }
6829 }
6830
6831 return foundentry;
6832 }
6833
6834 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid)6835 necp_create_uuid_service_id_mapping(uuid_t uuid)
6836 {
6837 u_int32_t local_id = 0;
6838 struct necp_uuid_id_mapping *existing_mapping = NULL;
6839
6840 if (uuid_is_null(uuid)) {
6841 return NECP_NULL_SERVICE_ID;
6842 }
6843
6844 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6845
6846 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6847 if (existing_mapping != NULL) {
6848 local_id = existing_mapping->id;
6849 os_ref_retain_locked(&existing_mapping->refcount);
6850 } else {
6851 struct necp_uuid_id_mapping *new_mapping = NULL;
6852 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6853 Z_WAITOK | Z_NOFAIL);
6854 uuid_copy(new_mapping->uuid, uuid);
6855 new_mapping->id = necp_get_new_uuid_id(true);
6856 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6857
6858 LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
6859
6860 local_id = new_mapping->id;
6861 }
6862
6863 return local_id;
6864 }
6865
6866 static bool
necp_remove_uuid_service_id_mapping(uuid_t uuid)6867 necp_remove_uuid_service_id_mapping(uuid_t uuid)
6868 {
6869 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6870
6871 if (uuid_is_null(uuid)) {
6872 return TRUE;
6873 }
6874
6875 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6876
6877 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6878 if (existing_mapping != NULL) {
6879 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6880 LIST_REMOVE(existing_mapping, chain);
6881 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6882 }
6883 return TRUE;
6884 }
6885
6886 return FALSE;
6887 }
6888
6889 static bool
necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)6890 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
6891 {
6892 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6893
6894 if (service_id == 0) {
6895 return TRUE;
6896 }
6897
6898 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6899
6900 existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
6901 if (existing_mapping != NULL) {
6902 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6903 LIST_REMOVE(existing_mapping, chain);
6904 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6905 }
6906 return TRUE;
6907 }
6908
6909 return FALSE;
6910 }
6911
6912 static bool
necp_kernel_socket_policies_update_uuid_table(void)6913 necp_kernel_socket_policies_update_uuid_table(void)
6914 {
6915 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6916
6917 if (necp_uuid_app_id_mappings_dirty) {
6918 uuid_t dummy_uuid = {};
6919 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6920 NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6921 return FALSE;
6922 }
6923
6924 if (necp_num_uuid_app_id_mappings > 0) {
6925 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6926 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--) {
6927 struct necp_uuid_id_mapping *mapping = NULL;
6928 LIST_FOREACH(mapping, uuid_list_head, chain) {
6929 if (mapping->table_usecount > 0 &&
6930 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6931 NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6932 }
6933 }
6934 }
6935 }
6936
6937 necp_uuid_app_id_mappings_dirty = FALSE;
6938 }
6939
6940 return TRUE;
6941 }
6942
6943 #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)
6944 static necp_kernel_policy_id
necp_kernel_ip_output_policy_add(necp_policy_order order,necp_policy_order suborder,u_int32_t session_order,int session_pid,u_int64_t condition_mask,u_int64_t condition_negated_mask,necp_kernel_policy_id cond_policy_id,ifnet_t cond_bound_interface,u_int32_t cond_last_interface_index,u_int16_t cond_protocol,union necp_sockaddr_union * cond_local_start,union necp_sockaddr_union * cond_local_end,u_int8_t cond_local_prefix,union necp_sockaddr_union * cond_remote_start,union necp_sockaddr_union * cond_remote_end,u_int8_t cond_remote_prefix,u_int16_t cond_packet_filter_tags,u_int16_t cond_scheme_port,u_int32_t cond_bound_interface_flags,u_int32_t cond_bound_interface_eflags,u_int32_t cond_bound_interface_xflags,u_int8_t cond_local_networks_flags,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)6945 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, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
6946 {
6947 struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6948 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6949
6950 new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6951 new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6952 new_kernel_policy->suborder = suborder;
6953 new_kernel_policy->order = order;
6954 new_kernel_policy->session_order = session_order;
6955 new_kernel_policy->session_pid = session_pid;
6956
6957 // Sanitize condition mask
6958 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6959 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6960 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6961 }
6962 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
6963 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
6964 }
6965 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6966 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6967 }
6968 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6969 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6970 }
6971 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6972
6973 // Set condition values
6974 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6975 new_kernel_policy->cond_policy_id = cond_policy_id;
6976 }
6977 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6978 if (cond_bound_interface) {
6979 ifnet_reference(cond_bound_interface);
6980 }
6981 new_kernel_policy->cond_bound_interface = cond_bound_interface;
6982 }
6983 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6984 new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6985 }
6986 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6987 new_kernel_policy->cond_protocol = cond_protocol;
6988 }
6989 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6990 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
6991 }
6992 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6993 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
6994 }
6995 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6996 new_kernel_policy->cond_local_prefix = cond_local_prefix;
6997 }
6998 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6999 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
7000 }
7001 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7002 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
7003 }
7004 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7005 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
7006 }
7007 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
7008 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
7009 }
7010 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7011 new_kernel_policy->cond_scheme_port = cond_scheme_port;
7012 }
7013 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
7014 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
7015 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
7016 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
7017 }
7018 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
7019 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
7020 }
7021
7022 new_kernel_policy->result = result;
7023 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
7024
7025 if (necp_debug) {
7026 NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
7027 }
7028 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
7029
7030 return new_kernel_policy ? new_kernel_policy->id : 0;
7031 }
7032
7033 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)7034 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
7035 {
7036 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7037 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7038
7039 if (policy_id == 0) {
7040 return NULL;
7041 }
7042
7043 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
7044 if (kernel_policy->id == policy_id) {
7045 return kernel_policy;
7046 }
7047 }
7048
7049 return NULL;
7050 }
7051
7052 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)7053 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
7054 {
7055 struct necp_kernel_ip_output_policy * __single policy = NULL;
7056
7057 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7058
7059 policy = necp_kernel_ip_output_policy_find(policy_id);
7060 if (policy) {
7061 LIST_REMOVE(policy, chain);
7062
7063 if (policy->cond_bound_interface) {
7064 ifnet_release(policy->cond_bound_interface);
7065 policy->cond_bound_interface = NULL;
7066 }
7067
7068 zfree(necp_ip_policy_zone, policy);
7069 return TRUE;
7070 }
7071
7072 return FALSE;
7073 }
7074
7075 static void
necp_kernel_ip_output_policies_dump_all(void)7076 necp_kernel_ip_output_policies_dump_all(void)
7077 {
7078 if (necp_debug) {
7079 struct necp_kernel_ip_output_policy *policy = NULL;
7080 int policy_i;
7081 int id_i;
7082 char result_string[MAX_RESULT_STRING_LEN];
7083 char proc_name_string[MAXCOMLEN + 1];
7084 memset(result_string, 0, MAX_RESULT_STRING_LEN);
7085 memset(proc_name_string, 0, MAXCOMLEN + 1);
7086
7087 NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
7088 NECPLOG0(LOG_DEBUG, "-----------\n");
7089 for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
7090 NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
7091 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++) {
7092 policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
7093 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
7094 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));
7095 }
7096 NECPLOG0(LOG_DEBUG, "-----------\n");
7097 }
7098 }
7099 }
7100
7101 static inline bool
necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy * upper_policy,struct necp_kernel_ip_output_policy * lower_policy)7102 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
7103 {
7104 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7105 if (upper_policy->session_order != lower_policy->session_order) {
7106 // A skip cannot override a policy of a different session
7107 return FALSE;
7108 } else {
7109 if (upper_policy->result_parameter.skip_policy_order == 0 ||
7110 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
7111 // This policy is beyond the skip
7112 return FALSE;
7113 } else {
7114 // This policy is inside the skip
7115 return TRUE;
7116 }
7117 }
7118 }
7119
7120 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
7121 return TRUE;
7122 }
7123
7124 static bool
necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy * policy,struct necp_kernel_ip_output_policy ** __indexable policy_array,int valid_indices)7125 necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy *policy, struct necp_kernel_ip_output_policy ** __indexable policy_array, int valid_indices)
7126 {
7127 bool can_skip = FALSE;
7128 u_int32_t highest_skip_session_order = 0;
7129 u_int32_t highest_skip_order = 0;
7130 int i;
7131 for (i = 0; i < valid_indices; i++) {
7132 struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
7133
7134 // For policies in a skip window, we can't mark conflicting policies as unnecessary
7135 if (can_skip) {
7136 if (highest_skip_session_order != compared_policy->session_order ||
7137 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
7138 // If we've moved on to the next session, or passed the skip window
7139 highest_skip_session_order = 0;
7140 highest_skip_order = 0;
7141 can_skip = FALSE;
7142 } else {
7143 // If this policy is also a skip, in can increase the skip window
7144 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7145 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
7146 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7147 }
7148 }
7149 continue;
7150 }
7151 }
7152
7153 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7154 // This policy is a skip. Set the skip window accordingly
7155 can_skip = TRUE;
7156 highest_skip_session_order = compared_policy->session_order;
7157 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7158 }
7159
7160 // The result of the compared policy must be able to block out this policy result
7161 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
7162 continue;
7163 }
7164
7165 // If new policy matches All Interfaces, compared policy must also
7166 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
7167 continue;
7168 }
7169
7170 // If new policy matches Local Networks, compared policy must also
7171 if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
7172 continue;
7173 }
7174
7175 // Default makes lower policies unnecessary always
7176 if (compared_policy->condition_mask == 0) {
7177 return TRUE;
7178 }
7179
7180 // Compared must be more general than policy, and include only conditions within policy
7181 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
7182 continue;
7183 }
7184
7185 // Negative conditions must match for the overlapping conditions
7186 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
7187 continue;
7188 }
7189
7190 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
7191 compared_policy->cond_policy_id != policy->cond_policy_id) {
7192 continue;
7193 }
7194
7195 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
7196 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
7197 continue;
7198 }
7199
7200 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
7201 compared_policy->cond_protocol != policy->cond_protocol) {
7202 continue;
7203 }
7204
7205 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7206 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7207 if (!necp_is_range_in_range(SA(&policy->cond_local_start), SA(&policy->cond_local_end), SA(&compared_policy->cond_local_start), SA(&compared_policy->cond_local_end))) {
7208 continue;
7209 }
7210 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7211 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
7212 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
7213 continue;
7214 }
7215 }
7216 }
7217
7218 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7219 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7220 if (!necp_is_range_in_range(SA(&policy->cond_remote_start), SA(&policy->cond_remote_end), SA(&compared_policy->cond_remote_start), SA(&compared_policy->cond_remote_end))) {
7221 continue;
7222 }
7223 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7224 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
7225 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
7226 continue;
7227 }
7228 }
7229 }
7230
7231 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
7232 compared_policy->cond_scheme_port != policy->cond_scheme_port) {
7233 continue;
7234 }
7235
7236 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
7237 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
7238 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
7239 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
7240 continue;
7241 }
7242
7243 return TRUE;
7244 }
7245
7246 return FALSE;
7247 }
7248
7249 static bool
necp_kernel_ip_output_policies_reprocess(void)7250 necp_kernel_ip_output_policies_reprocess(void)
7251 {
7252 int i;
7253 int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
7254 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7255
7256 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7257
7258 // Reset mask to 0
7259 necp_kernel_ip_output_policies_condition_mask = 0;
7260 necp_kernel_ip_output_policies_count = 0;
7261 necp_kernel_ip_output_policies_non_id_count = 0;
7262
7263 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7264 if (necp_kernel_ip_output_policies_map[i] != NULL) {
7265 kfree_type(struct necp_kernel_ip_output_policy *,
7266 necp_kernel_ip_output_policies_map_counts[i] + 1,
7267 necp_kernel_ip_output_policies_map[i]);
7268 necp_kernel_ip_output_policies_map[i] = NULL;
7269 }
7270
7271 // Init counts
7272 necp_kernel_ip_output_policies_map_counts[i] = 0;
7273 }
7274
7275 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7276 // Update mask
7277 necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
7278 necp_kernel_ip_output_policies_count++;
7279
7280 /* Update bucket counts:
7281 * Non-id and SKIP policies will be added to all buckets
7282 * Add local networks policy to all buckets for incoming IP
7283 */
7284 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7285 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7286 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7287 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7288 necp_kernel_ip_output_policies_map_counts[i]++;
7289 }
7290 }
7291 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
7292 necp_kernel_ip_output_policies_non_id_count++;
7293 } else {
7294 necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
7295 }
7296 }
7297
7298 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7299 if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
7300 // Allocate a NULL-terminated array of policy pointers for each bucket
7301 necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
7302 necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
7303 if (necp_kernel_ip_output_policies_map[i] == NULL) {
7304 goto fail;
7305 }
7306 }
7307 bucket_current_free_index[i] = 0;
7308 }
7309
7310 u_int32_t current_session_order = 0;
7311 u_int32_t current_session_last_non_skip_policy = 0;
7312
7313 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7314 // For each new session, find the last non-skip policy. We can
7315 // avoid adding any skip policies that don't actually skip over
7316 // any non-skip policies.
7317 if (current_session_order != kernel_policy->session_order) {
7318 current_session_order = kernel_policy->session_order;
7319 current_session_last_non_skip_policy = 0;
7320
7321 struct necp_kernel_ip_output_policy *inner_policy = NULL;
7322 LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
7323 if (inner_policy->session_order < current_session_order) {
7324 continue;
7325 }
7326 if (inner_policy->session_order > current_session_order) {
7327 break;
7328 }
7329 if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7330 continue;
7331 }
7332
7333 current_session_last_non_skip_policy = inner_policy->order;
7334 }
7335 }
7336
7337 if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7338 if (current_session_last_non_skip_policy == 0) {
7339 // No useful policies to skip over, don't add
7340 continue;
7341 }
7342 if (kernel_policy->order >= current_session_last_non_skip_policy) {
7343 // Skip policy is after the last useful policy, don't add
7344 continue;
7345 }
7346 }
7347
7348 // Insert pointers into map
7349 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7350 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7351 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7352 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7353 if (!necp_dedup_policies || !necp_kernel_ip_output_policy_is_unnecessary(kernel_policy, necp_kernel_ip_output_policies_map[i], bucket_current_free_index[i])) {
7354 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7355 bucket_current_free_index[i]++;
7356 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7357 }
7358 }
7359 } else {
7360 i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7361 if (!necp_dedup_policies || !necp_kernel_ip_output_policy_is_unnecessary(kernel_policy, necp_kernel_ip_output_policies_map[i], bucket_current_free_index[i])) {
7362 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7363 bucket_current_free_index[i]++;
7364 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7365 }
7366 }
7367 }
7368
7369 if (bucket_current_free_index[0] == 0) {
7370 // No non-id policies were actually added
7371 necp_kernel_ip_output_policies_non_id_count = 0;
7372
7373 // Also check if no policies at all were added
7374 bool policies_added = FALSE;
7375 for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7376 if (bucket_current_free_index[i] != 0) {
7377 policies_added = TRUE;
7378 break;
7379 }
7380 }
7381 if (!policies_added) {
7382 necp_kernel_ip_output_policies_condition_mask = 0;
7383 necp_kernel_ip_output_policies_count = 0;
7384 }
7385 }
7386
7387 necp_kernel_ip_output_policies_dump_all();
7388 return TRUE;
7389
7390 fail:
7391 // Free memory, reset mask to 0
7392 necp_kernel_ip_output_policies_condition_mask = 0;
7393 necp_kernel_ip_output_policies_count = 0;
7394 necp_kernel_ip_output_policies_non_id_count = 0;
7395 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7396 if (necp_kernel_ip_output_policies_map[i] != NULL) {
7397 kfree_type(struct necp_kernel_ip_output_policy *,
7398 necp_kernel_ip_output_policies_map_counts[i] + 1,
7399 necp_kernel_ip_output_policies_map[i]);
7400 necp_kernel_ip_output_policies_map[i] = NULL;
7401 }
7402 }
7403 return FALSE;
7404 }
7405
7406 // Outbound Policy Matching
7407 // ---------------------
7408 struct substring {
7409 size_t length;
7410 char * __sized_by(length) string;
7411 };
7412
7413 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7414 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7415 {
7416 struct substring sub = {};
7417 char * __indexable ptr = string;
7418 size_t len = string ? length : 0;
7419
7420 while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7421 ptr++;
7422 len--;
7423 }
7424
7425 while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7426 len--;
7427 }
7428
7429 sub.string = ptr;
7430 sub.length = len;
7431 return sub;
7432 }
7433
7434 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7435 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7436 {
7437 size_t trimmed_domain_length = 0;
7438 char *trimmed_domain = NULL;
7439 struct substring sub = necp_trim_dots_and_stars(string, length);
7440
7441 trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7442 trimmed_domain_length = sub.length + 1;
7443 if (trimmed_domain == NULL) {
7444 return NULL;
7445 }
7446
7447 strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7448 trimmed_domain[sub.length] = 0;
7449
7450 return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7451 }
7452
7453 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7454 necp_count_dots(char * __sized_by(length)string, size_t length)
7455 {
7456 int dot_count = 0;
7457 size_t i = 0;
7458
7459 for (i = 0; i < length; i++) {
7460 if (string[i] == '.') {
7461 dot_count++;
7462 }
7463 }
7464
7465 return dot_count;
7466 }
7467
7468 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7469 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7470 {
7471 if (parent.length <= suffix.length) {
7472 return FALSE;
7473 }
7474
7475 size_t length_difference = (parent.length - suffix.length);
7476
7477 if (require_dot_before_suffix) {
7478 if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7479 return FALSE;
7480 }
7481 }
7482
7483 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7484 return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7485 }
7486
7487 static bool
necp_hostname_matches_domain(struct substring hostname_substring,u_int8_t hostname_dot_count,char * domain __null_terminated,u_int8_t domain_dot_count)7488 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7489 {
7490 if (hostname_substring.string == NULL || domain == NULL) {
7491 return hostname_substring.string == domain;
7492 }
7493
7494 struct substring domain_substring;
7495 domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7496 domain_substring.length = strlen(domain);
7497
7498 if (hostname_dot_count == domain_dot_count) {
7499 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7500 if (hostname_substring.length == domain_substring.length &&
7501 strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7502 return TRUE;
7503 }
7504 } else if (domain_dot_count < hostname_dot_count) {
7505 if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7506 return TRUE;
7507 }
7508 }
7509
7510 return FALSE;
7511 }
7512
7513 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7514 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7515 {
7516 if (hostname_string == NULL ||
7517 domain_string == NULL) {
7518 return false;
7519 }
7520
7521 struct substring hostname_substring;
7522 hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7523 hostname_substring.length = strlen(hostname_string);
7524
7525 return necp_hostname_matches_domain(hostname_substring,
7526 necp_count_dots(hostname_substring.string, hostname_substring.length),
7527 domain_string,
7528 necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7529 }
7530
7531 #define NECP_MAX_STRING_LEN 1024
7532
7533 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7534 necp_copy_string(char * __sized_by(length)string, size_t length)
7535 {
7536 size_t copied_string_length = 0;
7537 char * __sized_by(copied_string_length) copied_string = NULL;
7538
7539 if (length > NECP_MAX_STRING_LEN) {
7540 return NULL;
7541 }
7542
7543 copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7544 copied_string_length = length + 1;
7545 if (copied_string == NULL) {
7546 return NULL;
7547 }
7548
7549 memcpy(copied_string, string, length);
7550 copied_string[length] = 0;
7551
7552 return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7553 }
7554
7555 static u_int32_t
necp_get_primary_direct_interface_index(void)7556 necp_get_primary_direct_interface_index(void)
7557 {
7558 u_int32_t interface_index = IFSCOPE_NONE;
7559
7560 ifnet_head_lock_shared();
7561 struct ifnet *ordered_interface = NULL;
7562 TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7563 const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7564 if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7565 functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7566 // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7567 interface_index = ordered_interface->if_index;
7568 break;
7569 }
7570 }
7571 ifnet_head_done();
7572
7573 return interface_index;
7574 }
7575
7576 static inline bool
necp_task_has_match_entitlement(task_t task)7577 necp_task_has_match_entitlement(task_t task)
7578 {
7579 return task != NULL &&
7580 (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7581 IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7582 }
7583
7584 // Loopback traffic from certain entitled process will be dropped
7585 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7586 necp_task_has_loopback_drop_entitlement(task_t task)
7587 {
7588 bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7589 if (drop) {
7590 necp_drop_loopback_count++;
7591 }
7592 return drop;
7593 }
7594
7595 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7596 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7597 {
7598 coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7599
7600 if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7601 // No parent, nothing to do
7602 return;
7603 }
7604
7605 task_t __single lead_task = coalition_get_leader(coal);
7606 if (lead_task != NULL) {
7607 info->is_entitled = necp_task_has_match_entitlement(lead_task);
7608 task_deallocate(lead_task);
7609 }
7610 }
7611
7612 // Some processes, due to particular entitlements, require using an NECP client to
7613 // access networking. Returns true if the result should be a Drop.
7614 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7615 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7616 {
7617 if (necp_is_platform_binary(proc)) {
7618 // This check is currently for the "on-demand-install-capable"
7619 // entitlement, which by definition cannot be a built-in platform
7620 // binary.
7621 return false;
7622 }
7623
7624 task_t __single task = proc_task(proc ? proc : current_proc());
7625
7626 if (!info->has_client &&
7627 task != NULL &&
7628 IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7629 // Drop connections that don't use NECP clients and have the
7630 // com.apple.developer.on-demand-install-capable entitlement.
7631 // This effectively restricts those processes to only using
7632 // an NECP-aware path for networking.
7633 return true;
7634 } else {
7635 return false;
7636 }
7637 }
7638
7639 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7640 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7641 {
7642 if (!necp_restrict_multicast || proc == NULL) {
7643 return false;
7644 }
7645
7646 // Check for multicast/broadcast here
7647 if (info->remote_addr.sa.sa_family == AF_INET) {
7648 if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7649 info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7650 return false;
7651 }
7652 } else if (info->remote_addr.sa.sa_family == AF_INET6) {
7653 if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7654 return false;
7655 }
7656 } else {
7657 // Not IPv4/IPv6
7658 return false;
7659 }
7660
7661 if (necp_is_platform_binary(proc)) {
7662 return false;
7663 }
7664
7665 const uint32_t platform = proc_platform(proc);
7666 const uint32_t sdk = proc_sdk(proc);
7667
7668 // Enforce for iOS, linked on or after version 14
7669 // If the caller set `check_minor_version`, only enforce starting at 14.5
7670 if ((platform != PLATFORM_IOS ||
7671 sdk == 0 ||
7672 (sdk >> 16) < 14 ||
7673 (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7674 return false;
7675 }
7676
7677 // Allow entitled processes to use multicast
7678 task_t __single task = proc_task(proc);
7679 if (task != NULL &&
7680 IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7681 return false;
7682 }
7683
7684 const uint32_t min_sdk = proc_min_sdk(proc);
7685 NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7686
7687 return true;
7688 }
7689
7690 #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)
7691 static void
necp_application_fillout_info_locked(task_t task,uuid_t application_uuid,uuid_t real_application_uuid,uuid_t responsible_application_uuid,char * account __null_terminated,char * domain __null_terminated,char * url __null_terminated,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)7692 necp_application_fillout_info_locked(task_t task, uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account __null_terminated, char *domain __null_terminated, char *url __null_terminated, 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)
7693 {
7694 memset(info, 0, sizeof(struct necp_socket_info));
7695
7696 info->pid = pid;
7697 info->pid_version = pid_version;
7698 info->uid = uid;
7699 info->real_uid = real_uid;
7700 info->protocol = protocol;
7701 info->bound_interface_index = bound_interface_index;
7702 info->traffic_class = traffic_class;
7703 info->has_client = has_client;
7704 info->has_system_signed_result = has_system_signed_result;
7705 info->drop_order = drop_order;
7706 info->client_flags = client_flags;
7707 info->is_loopback = is_loopback;
7708 info->is_delegated = is_delegated;
7709
7710 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7711 info->bound_interface_index != IFSCOPE_NONE) {
7712 ifnet_head_lock_shared();
7713 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7714 if (interface != NULL) {
7715 info->bound_interface_flags = interface->if_flags;
7716 info->bound_interface_eflags = interface->if_eflags;
7717 info->bound_interface_xflags = interface->if_xflags;
7718 }
7719 ifnet_head_done();
7720 }
7721
7722 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7723 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7724 if (existing_mapping) {
7725 info->application_id = existing_mapping->id;
7726 }
7727 }
7728
7729 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7730 if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7731 info->real_application_id = info->application_id;
7732 } else {
7733 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7734 if (existing_mapping) {
7735 info->real_application_id = existing_mapping->id;
7736 }
7737 }
7738 }
7739
7740 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7741 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7742 if (existing_mapping != NULL) {
7743 info->real_application_id = info->application_id;
7744 info->application_id = existing_mapping->id;
7745 info->used_responsible_pid = true;
7746 }
7747 }
7748
7749 if (info->used_responsible_pid) {
7750 proc = responsible_proc;
7751 }
7752
7753 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7754 info->is_entitled = necp_task_has_match_entitlement(task);
7755 if (!info->is_entitled) {
7756 // Task does not have entitlement, check the parent task
7757 necp_get_parent_is_entitled(task, info);
7758 }
7759 }
7760
7761 if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7762 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7763 if (necp_is_platform_binary(proc)) {
7764 info->is_platform_binary = true;
7765 } else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7766 info->is_platform_binary = true;
7767 info->used_responsible_pid = true;
7768 } else {
7769 info->is_platform_binary = false;
7770 }
7771 }
7772
7773 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7774 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7775 }
7776
7777 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7778 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7779 if (existing_mapping) {
7780 info->account_id = existing_mapping->id;
7781 }
7782 }
7783
7784 if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7785 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7786 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7787 info->domain = domain;
7788 }
7789
7790 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7791 info->url = url;
7792 }
7793
7794 if ((necp_data_tracing_level && necp_data_tracing_port) ||
7795 necp_restrict_multicast ||
7796 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7797 if (local_addr && local_addr->sa.sa_len > 0) {
7798 SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7799 if (local_port != 0) {
7800 info->local_addr.sin6.sin6_port = local_port;
7801 }
7802 } else {
7803 if (remote_addr && remote_addr->sa.sa_len > 0) {
7804 info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7805 info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7806 } else {
7807 info->local_addr.sin6.sin6_family = AF_INET6;
7808 info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7809 }
7810 if (local_port != 0) {
7811 info->local_addr.sin6.sin6_port = local_port;
7812 }
7813 }
7814 if (remote_addr && remote_addr->sa.sa_len > 0) {
7815 SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7816 if (remote_port != 0) {
7817 info->remote_addr.sin6.sin6_port = remote_port;
7818 }
7819 } else if (remote_port != 0) {
7820 info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7821 info->remote_addr.sin6.sin6_family = AF_INET6;
7822 info->remote_addr.sin6.sin6_port = remote_port;
7823 }
7824 }
7825
7826 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7827 info->scheme_port = scheme_port;
7828 }
7829 }
7830
7831 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7832 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7833 {
7834 struct kev_netpolicy_ifdenied ev_ifdenied;
7835
7836 bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7837
7838 ev_ifdenied.ev_data.epid = pid;
7839 uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7840 ev_ifdenied.ev_if_functional_type = if_functional_type;
7841
7842 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7843 }
7844
7845 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7846 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7847 {
7848 struct kev_netpolicy_netdenied ev_netdenied = {};
7849
7850 bzero(&ev_netdenied, sizeof(ev_netdenied));
7851
7852 ev_netdenied.ev_data.epid = pid;
7853 uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7854 ev_netdenied.ev_network_type = network_type;
7855
7856 netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7857 }
7858
7859 extern char *proc_name_address(void *p);
7860
7861 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7862 if (!has_checked_delegation_entitlement) { \
7863 has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7864 has_checked_delegation_entitlement = TRUE; \
7865 } \
7866 if (!has_delegation_entitlement) { \
7867 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7868 proc_name_address(_p), proc_pid(_p), _d); \
7869 break; \
7870 }
7871
7872 int
necp_application_find_policy_match_internal(proc_t proc,u_int8_t * __sized_by (parameters_size)parameters,u_int32_t parameters_size,struct necp_aggregate_result * returned_result,u_int32_t * flags,u_int32_t * reason,u_int required_interface_index,const union necp_sockaddr_union * override_local_addr,const union necp_sockaddr_union * override_remote_addr,struct necp_client_endpoint * returned_v4_gateway,struct necp_client_endpoint * returned_v6_gateway,struct rtentry ** returned_route,bool ignore_address,bool has_client,uuid_t * returned_override_euuid)7873 necp_application_find_policy_match_internal(proc_t proc,
7874 u_int8_t * __sized_by(parameters_size)parameters,
7875 u_int32_t parameters_size,
7876 struct necp_aggregate_result *returned_result,
7877 u_int32_t *flags,
7878 u_int32_t *reason,
7879 u_int required_interface_index,
7880 const union necp_sockaddr_union *override_local_addr,
7881 const union necp_sockaddr_union *override_remote_addr,
7882 struct necp_client_endpoint *returned_v4_gateway,
7883 struct necp_client_endpoint *returned_v6_gateway,
7884 struct rtentry **returned_route, bool ignore_address,
7885 bool has_client,
7886 uuid_t *returned_override_euuid)
7887 {
7888 int error = 0;
7889 size_t offset = 0;
7890
7891 struct necp_kernel_socket_policy *matched_policy = NULL;
7892 struct necp_socket_info info = {};
7893 necp_kernel_policy_filter filter_control_unit = 0;
7894 necp_kernel_policy_result service_action = 0;
7895 necp_kernel_policy_service service = { 0, 0 };
7896
7897 u_int16_t protocol = 0;
7898 u_int32_t bound_interface_index = required_interface_index;
7899 u_int32_t traffic_class = 0;
7900 u_int32_t client_flags = 0;
7901 u_int16_t scheme_port = 0;
7902 union necp_sockaddr_union local_addr;
7903 union necp_sockaddr_union remote_addr;
7904 bool no_remote_addr = FALSE;
7905 u_int8_t remote_family = 0;
7906 bool no_local_addr = FALSE;
7907 u_int16_t local_port = 0;
7908 u_int16_t remote_port = 0;
7909 u_int32_t remote_endpoint_type = 0;
7910 bool remote_address_is_empty = false;
7911 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7912 bool is_delegated = false;
7913
7914 if (override_local_addr) {
7915 memcpy(&local_addr, override_local_addr, sizeof(local_addr));
7916 } else {
7917 memset(&local_addr, 0, sizeof(local_addr));
7918 }
7919 if (override_remote_addr) {
7920 memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
7921 } else {
7922 memset(&remote_addr, 0, sizeof(remote_addr));
7923 }
7924
7925 // Initialize UID, PID, and UUIDs to the current process
7926 uid_t uid = 0;
7927 uid_t real_uid = 0;
7928 kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
7929 if (cred != NULL) {
7930 uid = kauth_cred_getuid(cred);
7931 real_uid = uid;
7932 }
7933 task_t __single task = proc_task(proc);
7934 pid_t pid = proc_pid(proc);
7935 int32_t pid_version = proc_pidversion(proc);
7936 uuid_t application_uuid;
7937 uuid_clear(application_uuid);
7938 uuid_t real_application_uuid;
7939 uuid_clear(real_application_uuid);
7940 proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
7941 uuid_copy(application_uuid, real_application_uuid);
7942 uuid_t responsible_application_uuid;
7943 uuid_clear(responsible_application_uuid);
7944
7945 char *domain __null_terminated = NULL;
7946 char *url __null_terminated = NULL;
7947 char *account __null_terminated = NULL;
7948
7949 #define NECP_MAX_REQUIRED_AGENTS 16
7950 u_int32_t num_required_agent_types = 0;
7951 struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
7952 memset(&required_agent_types, 0, sizeof(required_agent_types));
7953
7954 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
7955 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
7956 memset(&netagent_ids, 0, sizeof(netagent_ids));
7957 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
7958 int netagent_cursor;
7959
7960 bool has_checked_delegation_entitlement = false;
7961 bool has_delegation_entitlement = false;
7962 bool has_system_signed_result = false;
7963
7964 proc_t responsible_proc = PROC_NULL;
7965 proc_t effective_proc = proc;
7966 bool release_eproc = false;
7967 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
7968
7969 u_int32_t flow_divert_aggregate_unit = 0;
7970
7971 if (returned_result == NULL) {
7972 if (cred != NULL) {
7973 kauth_cred_unref(&cred);
7974 }
7975 return EINVAL;
7976 }
7977
7978 if (returned_v4_gateway != NULL) {
7979 memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
7980 }
7981
7982 if (returned_v6_gateway != NULL) {
7983 memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
7984 }
7985
7986 if (returned_override_euuid != NULL) {
7987 uuid_clear(*returned_override_euuid);
7988 }
7989
7990 memset(returned_result, 0, sizeof(struct necp_aggregate_result));
7991
7992 u_int32_t drop_order = necp_process_drop_order(cred);
7993
7994 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
7995
7996 lck_rw_lock_shared(&necp_kernel_policy_lock);
7997 if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
7998 if (necp_drop_all_order > 0 || drop_order > 0) {
7999 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8000 lck_rw_done(&necp_kernel_policy_lock);
8001 if (cred != NULL) {
8002 kauth_cred_unref(&cred);
8003 }
8004 return 0;
8005 }
8006 }
8007 lck_rw_done(&necp_kernel_policy_lock);
8008
8009 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
8010 u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
8011 u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
8012
8013 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
8014 // If the length is larger than what can fit in the remaining parameters size, bail
8015 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
8016 break;
8017 }
8018
8019 if (length > 0) {
8020 u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
8021 if (value != NULL) {
8022 switch (type) {
8023 case NECP_CLIENT_PARAMETER_APPLICATION: {
8024 if (length >= sizeof(uuid_t)) {
8025 if (uuid_compare(application_uuid, value) == 0) {
8026 // No delegation
8027 break;
8028 }
8029
8030 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
8031
8032 is_delegated = true;
8033 uuid_copy(application_uuid, value);
8034 }
8035 break;
8036 }
8037 case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
8038 if (length >= sizeof(uuid_t)) {
8039 if (uuid_compare(real_application_uuid, value) == 0) {
8040 // No delegation
8041 break;
8042 }
8043
8044 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
8045
8046 is_delegated = true;
8047 uuid_copy(real_application_uuid, value);
8048 }
8049 break;
8050 }
8051 case NECP_CLIENT_PARAMETER_PID: {
8052 if (length >= sizeof(pid_t)) {
8053 if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
8054 // No delegation
8055 break;
8056 }
8057
8058 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
8059
8060 is_delegated = true;
8061 memcpy(&pid, value, sizeof(pid_t));
8062 }
8063 break;
8064 }
8065 case NECP_CLIENT_PARAMETER_UID: {
8066 if (length >= sizeof(uid_t)) {
8067 if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
8068 // No delegation
8069 break;
8070 }
8071
8072 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
8073
8074 is_delegated = true;
8075 memcpy(&uid, value, sizeof(uid_t));
8076 }
8077 break;
8078 }
8079 case NECP_CLIENT_PARAMETER_DOMAIN: {
8080 char *ptr = (char *)value;
8081 ptr[length - 1] = 0;
8082 domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8083 break;
8084 }
8085 case NECP_CLIENT_PARAMETER_URL: {
8086 char *ptr = (char *)value;
8087 ptr[length - 1] = 0;
8088 url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8089 break;
8090 }
8091 case NECP_CLIENT_PARAMETER_ACCOUNT: {
8092 char *ptr = (char *)value;
8093 ptr[length - 1] = 0;
8094 account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8095 break;
8096 }
8097 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
8098 if (length >= sizeof(u_int32_t)) {
8099 memcpy(&traffic_class, value, sizeof(u_int32_t));
8100 }
8101 break;
8102 }
8103 case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
8104 if (length >= sizeof(u_int16_t)) {
8105 memcpy(&protocol, value, sizeof(u_int16_t));
8106 } else if (length >= sizeof(u_int8_t)) {
8107 memcpy(&protocol, value, sizeof(u_int8_t));
8108 }
8109 break;
8110 }
8111 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
8112 if (length <= IFXNAMSIZ && length > 0) {
8113 ifnet_t __single bound_interface = NULL;
8114 char interface_name[IFXNAMSIZ];
8115 memcpy(interface_name, value, length);
8116 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
8117 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
8118 bound_interface_index = bound_interface->if_index;
8119 ifnet_release(bound_interface);
8120 }
8121 }
8122 break;
8123 }
8124 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
8125 if (ignore_address || override_local_addr) {
8126 break;
8127 }
8128
8129 if (length >= sizeof(struct necp_policy_condition_addr)) {
8130 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8131 if (necp_address_is_valid(&address_struct->address.sa)) {
8132 memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
8133 }
8134 }
8135 break;
8136 }
8137 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
8138 if (ignore_address || override_remote_addr) {
8139 break;
8140 }
8141
8142 if (length >= sizeof(struct necp_policy_condition_addr)) {
8143 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8144 if (necp_address_is_valid(&address_struct->address.sa)) {
8145 memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
8146 }
8147 }
8148 break;
8149 }
8150 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
8151 if (ignore_address || override_local_addr) {
8152 break;
8153 }
8154
8155 if (length >= sizeof(struct necp_client_endpoint)) {
8156 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8157 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
8158 endpoint->u.endpoint.endpoint_port != 0) {
8159 // Save port
8160 local_port = endpoint->u.endpoint.endpoint_port;
8161 }
8162 }
8163 break;
8164 }
8165 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
8166 if (ignore_address || override_remote_addr) {
8167 break;
8168 }
8169
8170 if (length >= sizeof(struct necp_client_endpoint)) {
8171 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8172 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
8173 remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
8174 if (endpoint->u.endpoint.endpoint_port != 0) {
8175 // Save port
8176 remote_port = endpoint->u.endpoint.endpoint_port;
8177 }
8178 } else if (necp_addr_is_empty(&endpoint->u.sa)) {
8179 remote_address_is_empty = true;
8180 }
8181 }
8182 break;
8183 }
8184 case NECP_CLIENT_PARAMETER_FLAGS: {
8185 if (length >= sizeof(client_flags)) {
8186 memcpy(&client_flags, value, sizeof(client_flags));
8187 }
8188 break;
8189 }
8190 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
8191 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
8192 if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8193 break;
8194 }
8195 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
8196 memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
8197 num_required_agent_types++;
8198 }
8199 break;
8200 }
8201 case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
8202 if (length >= sizeof(scheme_port)) {
8203 memcpy(&scheme_port, value, sizeof(scheme_port));
8204 }
8205 break;
8206 }
8207 case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
8208 has_system_signed_result = true;
8209 struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
8210 if (length >= sizeof(struct necp_client_validatable)) {
8211 // Check for system-signed sign_type values
8212 if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
8213 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
8214 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
8215 has_system_signed_result = true;
8216 }
8217 }
8218 break;
8219 }
8220 default: {
8221 break;
8222 }
8223 }
8224 }
8225 }
8226
8227 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
8228 }
8229
8230 // Check for loopback exception
8231 if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
8232 if (necp_task_has_loopback_drop_entitlement(task)) {
8233 // Disallow certain entitled processes to send loopback traffic
8234 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8235 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8236 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8237 if (cred != NULL) {
8238 kauth_cred_unref(&cred);
8239 }
8240 return 0;
8241 }
8242 if (necp_pass_loopback > 0) {
8243 bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
8244 }
8245 } else if (bound_interface_index != IFSCOPE_NONE) {
8246 // Check for inter-process exception
8247 struct sockaddr *dst = SA(&remote_addr.sa);
8248 if (dst->sa_family == AF_INET6) {
8249 struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
8250 if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
8251 ifnet_head_lock_shared();
8252 ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
8253 if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
8254 bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
8255 }
8256 ifnet_head_done();
8257 }
8258 }
8259 }
8260
8261 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
8262 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8263 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8264 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8265 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
8266 returned_result->routed_interface_index = lo_ifp->if_index;
8267 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8268 } else {
8269 returned_result->routed_interface_index = bound_interface_index;
8270 }
8271 if (cred != NULL) {
8272 kauth_cred_unref(&cred);
8273 }
8274 return 0;
8275 }
8276
8277 if (drop_order != 0) {
8278 if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
8279 client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
8280 ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
8281 // Allow listeners, inbound connections without remote addresses, and
8282 // application service connections to bypass the unentitled drop order,
8283 // to allow them to connect to application services (not directly over
8284 // physical networking interfaces)
8285 drop_order = 0;
8286 }
8287 }
8288
8289 if (proc_pid(effective_proc) != pid) {
8290 proc_t found_proc = proc_find(pid);
8291 if (found_proc != PROC_NULL) {
8292 effective_proc = found_proc;
8293 pid_version = proc_pidversion(effective_proc);
8294 release_eproc = true;
8295 }
8296 }
8297 #if defined(XNU_TARGET_OS_OSX)
8298 if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
8299 proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
8300 responsible_proc = proc_find(effective_proc->p_responsible_pid);
8301 }
8302 #endif /* defined(XNU_TARGET_OS_OSX) */
8303
8304 // Lock
8305 lck_rw_lock_shared(&necp_kernel_policy_lock);
8306
8307 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
8308 size_t route_rule_id_array_count = 0;
8309 necp_application_fillout_info_locked(task, application_uuid, real_application_uuid, responsible_application_uuid, account, domain, url, pid, pid_version, uid, real_uid, protocol, bound_interface_index, traffic_class, &local_addr, &remote_addr, local_port, remote_port, has_client, has_system_signed_result, proc, effective_proc, responsible_proc, drop_order, client_flags, scheme_port, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), is_delegated);
8310
8311 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
8312 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
8313
8314 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
8315 matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
8316 &info,
8317 &filter_control_unit,
8318 route_rule_id_array,
8319 &route_rule_id_array_count,
8320 MAX_AGGREGATE_ROUTE_RULES,
8321 &service_action,
8322 &service,
8323 netagent_ids,
8324 NECP_MAX_NETAGENTS,
8325 netagent_use_flags,
8326 NECP_MAX_NETAGENTS,
8327 required_agent_types,
8328 num_required_agent_types,
8329 info.used_responsible_pid ? responsible_proc : effective_proc,
8330 0,
8331 &skip_policy_id,
8332 NULL,
8333 &drop_dest_policy_result,
8334 &drop_all_bypass,
8335 &flow_divert_aggregate_unit,
8336 NULL,
8337 debug);
8338
8339 // Check for loopback exception again after the policy match
8340 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
8341 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
8342 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
8343 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8344 returned_result->filter_control_unit = 0;
8345 } else {
8346 returned_result->filter_control_unit = filter_control_unit;
8347 }
8348
8349 if (flow_divert_aggregate_unit > 0) {
8350 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8351 }
8352
8353 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8354 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8355 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8356 returned_result->routed_interface_index = lo_ifp->if_index;
8357 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8358 error = 0;
8359 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8360 goto done;
8361 }
8362
8363 if (matched_policy) {
8364 returned_result->policy_id = matched_policy->id;
8365 returned_result->skip_policy_id = skip_policy_id;
8366 returned_result->routing_result = matched_policy->result;
8367 memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8368 if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8369 uuid_copy(*returned_override_euuid, responsible_application_uuid);
8370 }
8371 } else {
8372 bool drop_all = false;
8373 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8374 // Mark socket as a drop if drop_all is set
8375 drop_all = true;
8376 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8377 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8378 }
8379 }
8380 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8381 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8382 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8383 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8384 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8385 } else {
8386 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8387 returned_result->skip_policy_id = skip_policy_id;
8388 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8389 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8390 }
8391 }
8392 if (necp_check_missing_client_drop(proc, &info) ||
8393 necp_check_restricted_multicast_drop(proc, &info, false)) {
8394 // Mark as drop
8395 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8396 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8397 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8398 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8399 }
8400 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8401 returned_result->filter_control_unit = 0;
8402 } else {
8403 returned_result->filter_control_unit = filter_control_unit;
8404 }
8405
8406 if (flow_divert_aggregate_unit > 0) {
8407 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8408 }
8409
8410 returned_result->service_action = service_action;
8411
8412 // Fetch service registration
8413 if (service.identifier != 0) {
8414 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
8415 if (mapping != NULL) {
8416 struct necp_service_registration *service_registration = NULL;
8417 uuid_copy(returned_result->service_uuid, mapping->uuid);
8418 returned_result->service_data = service.data;
8419 if (service.identifier == NECP_NULL_SERVICE_ID) {
8420 // NULL service is always 'registered'
8421 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8422 } else {
8423 LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
8424 if (service.identifier == service_registration->service_id) {
8425 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8426 break;
8427 }
8428 }
8429 }
8430 }
8431 }
8432
8433 // Handle netagents
8434 size_t netagent_i = 0;
8435 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8436 struct necp_uuid_id_mapping *mapping = NULL;
8437 u_int32_t netagent_id = netagent_ids[netagent_cursor];
8438 if (netagent_id == 0) {
8439 continue;
8440 }
8441 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8442 if (mapping != NULL) {
8443 uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8444 returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8445 netagent_i++;
8446 }
8447
8448 // If the flags say to remove, clear the local copy
8449 if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8450 netagent_ids[netagent_cursor] = 0;
8451 }
8452 }
8453
8454 // Do routing evaluation
8455 u_int output_bound_interface = bound_interface_index;
8456 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8457 output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8458 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8459 output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8460 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8461 output_bound_interface = necp_get_primary_direct_interface_index();
8462 if (output_bound_interface == IFSCOPE_NONE) {
8463 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8464 } else {
8465 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8466 returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8467 }
8468 }
8469
8470 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8471 returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8472 if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8473 // Trigger the event that we dropped due to a local network policy
8474 #if defined(XNU_TARGET_OS_OSX)
8475 bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8476 necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8477 should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8478 NETPOLICY_NETWORKTYPE_LOCAL);
8479 #else
8480 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8481 #endif
8482 }
8483 if (reason != NULL) {
8484 *reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8485 }
8486 }
8487
8488 if (local_addr.sa.sa_len == 0 ||
8489 (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8490 (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8491 no_local_addr = TRUE;
8492 }
8493
8494 if (remote_addr.sa.sa_len == 0 ||
8495 (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8496 (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8497 no_remote_addr = TRUE;
8498 remote_family = remote_addr.sa.sa_family;
8499 }
8500
8501 returned_result->routed_interface_index = 0;
8502 struct rtentry *rt = NULL;
8503 if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8504 // Treat the output bound interface as the routed interface for local address
8505 // validation later.
8506 returned_result->routed_interface_index = output_bound_interface;
8507 } else {
8508 if (no_remote_addr) {
8509 memset(&remote_addr, 0, sizeof(remote_addr));
8510 if (remote_family == AF_INET6) {
8511 // Reset address to ::
8512 remote_addr.sa.sa_family = AF_INET6;
8513 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8514 } else {
8515 // Reset address to 0.0.0.0
8516 remote_addr.sa.sa_family = AF_INET;
8517 remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8518 }
8519 }
8520
8521 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8522 output_bound_interface);
8523
8524 if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8525 IS_INTF_CLAT46(rt->rt_ifp)) {
8526 rtfree(rt);
8527 rt = NULL;
8528 returned_result->routed_interface_index = 0;
8529 }
8530
8531 if (no_remote_addr && remote_family == AF_UNSPEC &&
8532 (rt == NULL || rt->rt_ifp == NULL)) {
8533 // Route lookup for default IPv4 failed, try IPv6
8534
8535 // Cleanup old route if necessary
8536 if (rt != NULL) {
8537 rtfree(rt);
8538 rt = NULL;
8539 }
8540
8541 // Reset address to ::
8542 memset(&remote_addr, 0, sizeof(remote_addr));
8543 remote_addr.sa.sa_family = AF_INET6;
8544 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8545
8546 // Get route
8547 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8548 output_bound_interface);
8549 }
8550
8551 if (rt != NULL &&
8552 rt->rt_ifp != NULL) {
8553 returned_result->routed_interface_index = rt->rt_ifp->if_index;
8554 /*
8555 * For local addresses, we allow the interface scope to be
8556 * either the loopback interface or the interface hosting the
8557 * local address.
8558 */
8559 if (bound_interface_index != IFSCOPE_NONE &&
8560 rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8561 (output_bound_interface == lo_ifp->if_index ||
8562 rt->rt_ifp->if_index == lo_ifp->if_index ||
8563 rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8564 struct sockaddr_storage dst;
8565 unsigned int ifscope = bound_interface_index;
8566
8567 /*
8568 * Transform dst into the internal routing table form
8569 */
8570 (void) sa_copy(SA(&remote_addr),
8571 &dst, &ifscope);
8572
8573 if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8574 rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8575 returned_result->routed_interface_index =
8576 bound_interface_index;
8577 }
8578 }
8579 }
8580 }
8581
8582 if (returned_result->routed_interface_index != 0 &&
8583 returned_result->routed_interface_index != lo_ifp->if_index && // Loopback can accept any local address
8584 !no_local_addr) {
8585 // Transform local_addr into the ifaddr form
8586 // IPv6 Scope IDs are always embedded in the ifaddr list
8587 struct sockaddr_storage local_address_sanitized;
8588 u_int ifscope = IFSCOPE_NONE;
8589 (void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8590 SIN(&local_address_sanitized)->sin_port = 0;
8591 if (local_address_sanitized.ss_family == AF_INET6) {
8592 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8593 SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8594 }
8595 }
8596
8597 // Validate local address on routed interface
8598 struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8599 if (ifa == NULL) {
8600 // Interface address not found, reject route
8601 returned_result->routed_interface_index = 0;
8602 if (rt != NULL) {
8603 rtfree(rt);
8604 rt = NULL;
8605 }
8606 } else {
8607 ifaddr_release(ifa);
8608 ifa = NULL;
8609 }
8610 }
8611
8612 if (flags != NULL) {
8613 #if SKYWALK
8614 if (kernel_is_macos_or_server()) {
8615 enum net_filter_event_subsystems filters = net_filter_event_get_state();
8616
8617 if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8618 *flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8619 }
8620 if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8621 *flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8622 }
8623 if (filters & NET_FILTER_EVENT_ALF) {
8624 *flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8625 }
8626 if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8627 *flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8628 }
8629 }
8630 #endif /* SKYWALK */
8631 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8632 // Check for local/direct
8633 bool is_local = FALSE;
8634 if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8635 is_local = TRUE;
8636 } else if (returned_result->routed_interface_index != 0 &&
8637 !no_remote_addr) {
8638 // Clean up the address before comparison with interface addresses
8639
8640 // Transform remote_addr into the ifaddr form
8641 // IPv6 Scope IDs are always embedded in the ifaddr list
8642 struct sockaddr_storage remote_address_sanitized;
8643 u_int ifscope = IFSCOPE_NONE;
8644 (void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8645 SIN(&remote_address_sanitized)->sin_port = 0;
8646 if (remote_address_sanitized.ss_family == AF_INET6) {
8647 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8648 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8649 }
8650 }
8651
8652 // Check if remote address is an interface address
8653 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8654 if (ifa != NULL && ifa->ifa_ifp != NULL) {
8655 u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8656 if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8657 if_index_for_remote_addr == lo_ifp->if_index) {
8658 is_local = TRUE;
8659 }
8660 }
8661 if (ifa != NULL) {
8662 ifaddr_release(ifa);
8663 ifa = NULL;
8664 }
8665 }
8666
8667 if (is_local) {
8668 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8669 } else if (rt != NULL) {
8670 if (rt->rt_flags & RTF_GLOBAL) {
8671 *flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8672 } else if (!(rt->rt_flags & RTF_GATEWAY) &&
8673 (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8674 // Route is directly accessible
8675 *flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8676 }
8677 }
8678
8679 if (rt != NULL &&
8680 rt->rt_ifp != NULL) {
8681 // Check probe status
8682 if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8683 *flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8684 }
8685
8686 if (if_link_heuristics_enabled(rt->rt_ifp)) {
8687 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_HEURISTICS;
8688 }
8689
8690 if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8691 struct if_cellular_status_v1 *ifsr;
8692
8693 ifnet_lock_shared(rt->rt_ifp);
8694 lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8695
8696 if (rt->rt_ifp->if_link_status != NULL) {
8697 ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8698
8699 if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8700 if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8701 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8702 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8703 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8704 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8705 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8706 }
8707 }
8708 }
8709 lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8710 ifnet_lock_done(rt->rt_ifp);
8711 }
8712
8713 // Check link quality
8714 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8715 (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8716 rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8717 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8718 }
8719
8720 // Check QoS marking (fastlane)
8721 for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8722 if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8723 *flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8724 // If the route can use QoS markings, stop iterating route rules
8725 break;
8726 }
8727 }
8728
8729 if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8730 *flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8731 }
8732
8733 if (traffic_class == SO_TC_BK_SYS) {
8734 // Block BK_SYS traffic if interface is throttled
8735 u_int32_t throttle_level = 0;
8736 if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8737 if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8738 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8739 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8740 }
8741 }
8742 }
8743 }
8744 }
8745
8746 u_int interface_to_check = returned_result->routed_interface_index;
8747 if (interface_to_check == 0) {
8748 interface_to_check = output_bound_interface;
8749 }
8750 union necp_sockaddr_union default_address;
8751 struct rtentry *v4Route = NULL;
8752 struct rtentry *v6Route = NULL;
8753
8754 memset(&default_address, 0, sizeof(default_address));
8755
8756 // Reset address to 0.0.0.0
8757 default_address.sa.sa_family = AF_INET;
8758 default_address.sa.sa_len = sizeof(struct sockaddr_in);
8759 v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8760 returned_result->routed_interface_index);
8761
8762 // Reset address to ::
8763 default_address.sa.sa_family = AF_INET6;
8764 default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8765 v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8766 returned_result->routed_interface_index);
8767
8768 if (v4Route != NULL) {
8769 if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8770 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8771 }
8772 if (returned_v4_gateway != NULL &&
8773 v4Route->rt_gateway != NULL &&
8774 v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8775 memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8776 memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8777 }
8778 rtfree(v4Route);
8779 v4Route = NULL;
8780 }
8781
8782 if (v6Route != NULL) {
8783 if (v6Route->rt_ifp != NULL) {
8784 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8785
8786 if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8787 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8788 }
8789 }
8790 if (returned_v6_gateway != NULL &&
8791 v6Route->rt_gateway != NULL &&
8792 v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8793 SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8794 }
8795 rtfree(v6Route);
8796 v6Route = NULL;
8797 }
8798 }
8799
8800 // Take two passes through the rule list: first for rules that don't match based on agents,
8801 // second for rules that match based on agents. Since rules can modify the agent list itself,
8802 // this makes the logic more deterministic. This allows a non-agent matching rule to remove
8803 // an agent before it is used for matching later.
8804 size_t route_rule_index = 0;
8805 bool second_pass = false;
8806 while (route_rule_index < route_rule_id_array_count) {
8807 bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8808 if (rule_matches_agents != second_pass) {
8809 // Process rules that match based on agents only in the second pass
8810 route_rule_index++;
8811 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8812 route_rule_index = 0;
8813 second_pass = true;
8814 }
8815 continue;
8816 }
8817
8818 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8819 bool route_is_allowed = necp_route_is_allowed(rt, NULL, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &interface_type_denied);
8820 if (!route_is_allowed) {
8821 // If the route is blocked, treat the lookup as a drop
8822 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8823 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8824
8825 if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8826 if (reason != NULL) {
8827 if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8828 *reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8829 } else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8830 *reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8831 }
8832 }
8833 necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8834 }
8835 // If the route gets denied, stop matching rules
8836 break;
8837 }
8838
8839 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8840 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8841 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8842 route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8843 if (flow_divert_control_unit != 0) {
8844 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8845 returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8846 }
8847 if (flow_divert_aggregate_unit != 0) {
8848 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8849 }
8850 }
8851
8852 // Check if there is a route rule that adds or removes an agent
8853 bool remove = false;
8854 u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8855 if (netagent_id != 0) {
8856 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8857 if (mapping != NULL) {
8858 bool agent_already_present = false;
8859 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8860 if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8861 // Found the agent already present
8862 agent_already_present = true;
8863 if (remove) {
8864 // Mark as remove if necessary
8865 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8866 }
8867 } else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8868 // Found open slot
8869 if (!agent_already_present) {
8870 uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8871 if (remove) {
8872 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8873 } else {
8874 returned_result->netagent_use_flags[netagent_cursor] = 0;
8875 }
8876 }
8877 break;
8878 }
8879 }
8880 }
8881
8882 // Update the local netagent_ids array for future evaluations
8883 if (remove) {
8884 // Check if the agent ID is in the array, and remove it
8885 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8886 if (netagent_id == netagent_ids[netagent_cursor]) {
8887 netagent_ids[netagent_cursor] = 0;
8888 }
8889 }
8890 } else {
8891 // Check if the agent ID is not yet in the array, and add it
8892 bool found = false;
8893 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8894 if (netagent_id == netagent_ids[netagent_cursor]) {
8895 found = true;
8896 break;
8897 }
8898 }
8899 if (!found) {
8900 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8901 if (netagent_ids[netagent_cursor] == 0) {
8902 // Empty slot, add the agent
8903 netagent_ids[netagent_cursor] = netagent_id;
8904 break;
8905 }
8906 }
8907 }
8908 }
8909 }
8910
8911 route_rule_index++;
8912 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8913 route_rule_index = 0;
8914 second_pass = true;
8915 }
8916 }
8917
8918 if (rt != NULL && rt->rt_ifp != NULL) {
8919 const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8920 const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8921 const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8922 IFNET_IS_EXPENSIVE(rt->rt_ifp));
8923 const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8924 IFNET_IS_CONSTRAINED(rt->rt_ifp));
8925 const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
8926 IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
8927 !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT)));
8928
8929 const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
8930 if (!is_listener && !is_browser) {
8931 if (reason != NULL) {
8932 if (expensive_prohibited) {
8933 *reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8934 } else if (constrained_prohibited) {
8935 *reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8936 } else if (ultra_constrained_not_allowed) {
8937 *reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8938 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_ULTRA_CONSTRAINED);
8939 }
8940 }
8941 if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
8942 // If a property of the interface was not allowed, treat it as a drop
8943 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8944 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8945 }
8946 }
8947 }
8948
8949 if (rt != NULL) {
8950 if (returned_route != NULL) {
8951 *returned_route = rt;
8952 } else {
8953 rtfree(rt);
8954 }
8955 rt = NULL;
8956 }
8957
8958 done:
8959 // Unlock
8960 lck_rw_done(&necp_kernel_policy_lock);
8961
8962 if (release_eproc && effective_proc != PROC_NULL) {
8963 proc_rele(effective_proc);
8964 }
8965 #if defined(XNU_TARGET_OS_OSX)
8966 if (responsible_proc != PROC_NULL) {
8967 proc_rele(responsible_proc);
8968 }
8969 #endif
8970
8971 if (cred != NULL) {
8972 kauth_cred_unref(&cred);
8973 }
8974
8975 return error;
8976 }
8977
8978 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)8979 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
8980 {
8981 struct rtentry *rt = NULL;
8982 bool is_local = FALSE;
8983
8984 if (remote_addr == NULL) {
8985 return NULL;
8986 }
8987
8988 if (remote_addr->sa.sa_len == 0 ||
8989 (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8990 (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8991 return FALSE;
8992 }
8993
8994 // Lookup route regardless of the scoped interface to check if
8995 // remote address is in a local network.
8996 rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
8997
8998 if (rt == NULL) {
8999 goto done;
9000 }
9001 if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
9002 goto free_rt;
9003 }
9004 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
9005
9006 free_rt:
9007 rtfree(rt);
9008
9009 done:
9010 return is_local;
9011 }
9012
9013 static bool
necp_socket_check_policy(struct necp_kernel_socket_policy * kernel_policy,necp_app_id app_id,necp_app_id real_app_id,uint8_t is_entitled,u_int32_t account_id,struct substring domain,u_int8_t domain_dot_count,const char * url __null_terminated,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 * __counted_by (num_required_agent_types)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,struct socket * socket)9014 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
9015 necp_app_id app_id,
9016 necp_app_id real_app_id,
9017 uint8_t is_entitled,
9018 u_int32_t account_id,
9019 struct substring domain,
9020 u_int8_t domain_dot_count,
9021 const char *url __null_terminated,
9022 pid_t pid,
9023 int32_t pid_version,
9024 uid_t uid,
9025 uid_t real_uid,
9026 u_int32_t bound_interface_index,
9027 u_int32_t traffic_class,
9028 u_int16_t protocol,
9029 union necp_sockaddr_union *local,
9030 union necp_sockaddr_union *remote,
9031 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9032 u_int32_t num_required_agent_types,
9033 bool has_client,
9034 uint32_t client_flags,
9035 int is_platform_binary,
9036 bool has_signed_result,
9037 proc_t proc,
9038 u_int16_t pf_tag,
9039 u_int16_t scheme_port,
9040 struct rtentry *rt,
9041 bool is_loopback,
9042 int debug,
9043 bool real_is_platform_binary,
9044 u_int32_t bound_interface_flags,
9045 u_int32_t bound_interface_eflags,
9046 u_int32_t bound_interface_xflags,
9047 struct necp_socket_info *info,
9048 bool is_delegated,
9049 struct socket *socket)
9050 {
9051 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9052 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9053 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9054 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9055 "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
9056 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9057 if (bound_interface_index == cond_bound_interface_index) {
9058 // No match, matches forbidden interface
9059 return FALSE;
9060 }
9061 } else {
9062 if (bound_interface_index != cond_bound_interface_index) {
9063 // No match, does not match required interface
9064 return FALSE;
9065 }
9066 }
9067 }
9068 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9069 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9070 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9071 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9072 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9073 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9074 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9075 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9076 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9077 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9078 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9079 // No match, matches some forbidden interface flags
9080 return FALSE;
9081 }
9082 } else {
9083 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9084 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9085 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9086 // No match, does not match some required interface xflags
9087 return FALSE;
9088 }
9089 }
9090 }
9091 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9092 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9093 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
9094 if (bound_interface_index != 0) {
9095 // No match, requires a non-bound packet
9096 return FALSE;
9097 }
9098 }
9099 }
9100
9101 if (kernel_policy->condition_mask == 0) {
9102 return TRUE;
9103 }
9104
9105 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9106 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
9107 "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
9108 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
9109 if (app_id == kernel_policy->cond_app_id) {
9110 // No match, matches forbidden application
9111 return FALSE;
9112 }
9113 } else {
9114 if (app_id != kernel_policy->cond_app_id) {
9115 // No match, does not match required application
9116 return FALSE;
9117 }
9118 }
9119
9120 // Check signing identifier only after APP ID matched
9121 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
9122 kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9123 u_int8_t matched = necp_boolean_state_false;
9124 const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
9125 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
9126 "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
9127 kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
9128 signing_id ? signing_id : "<n/a>");
9129 if (signing_id != NULL) {
9130 if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
9131 matched = necp_boolean_state_true;
9132 }
9133 }
9134
9135 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9136 if (matched == necp_boolean_state_true) {
9137 return FALSE;
9138 }
9139 } else {
9140 if (matched != necp_boolean_state_true) {
9141 return FALSE;
9142 }
9143 }
9144 }
9145 }
9146
9147 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9148 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
9149 "NECP_KERNEL_CONDITION_REAL_APP_ID",
9150 kernel_policy->cond_real_app_id, real_app_id);
9151 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9152 if (real_app_id == kernel_policy->cond_real_app_id) {
9153 // No match, matches forbidden application
9154 return FALSE;
9155 }
9156 } else {
9157 if (real_app_id != kernel_policy->cond_real_app_id) {
9158 // No match, does not match required application
9159 return FALSE;
9160 }
9161 }
9162 }
9163
9164 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9165 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
9166 if (!has_client) {
9167 return FALSE;
9168 }
9169 }
9170
9171 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9172 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
9173 if (!is_entitled) {
9174 // Process is missing entitlement
9175 return FALSE;
9176 }
9177 }
9178
9179 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9180 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY, "NECP_KERNEL_CONDITION_PLATFORM_BINARY", 0, is_platform_binary);
9181 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9182 if (is_platform_binary) {
9183 // Process is platform binary
9184 return FALSE;
9185 }
9186 } else {
9187 if (!is_platform_binary) {
9188 // Process is not platform binary
9189 return FALSE;
9190 }
9191 }
9192 }
9193
9194 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9195 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
9196 if (has_signed_result == 0) {
9197 // Client did not have a system-signed result
9198 return FALSE;
9199 }
9200 }
9201
9202 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
9203 if (proc != NULL) {
9204 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
9205 kernel_policy->cond_sdk_version.platform,
9206 kernel_policy->cond_sdk_version.min_version,
9207 kernel_policy->cond_sdk_version.version,
9208 proc_platform(proc),
9209 proc_min_sdk(proc),
9210 proc_sdk(proc));
9211 if (kernel_policy->cond_sdk_version.platform != 0) {
9212 if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
9213 // Process does not match platform
9214 return FALSE;
9215 }
9216 }
9217
9218 if (kernel_policy->cond_sdk_version.min_version != 0) {
9219 if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
9220 // Process min version is older than required min version
9221 return FALSE;
9222 }
9223 }
9224
9225 if (kernel_policy->cond_sdk_version.version != 0) {
9226 if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
9227 // Process SDK version is older than required version
9228 return FALSE;
9229 }
9230 }
9231 }
9232 }
9233
9234 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
9235 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
9236 if (kernel_policy->cond_custom_entitlement != NULL) {
9237 if (proc == NULL) {
9238 // No process found, cannot check entitlement
9239 return FALSE;
9240 }
9241 task_t __single task = proc_task(proc);
9242 if (task == NULL ||
9243 !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
9244 // Process is missing custom entitlement
9245 return FALSE;
9246 }
9247 }
9248 }
9249
9250 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9251 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
9252 "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
9253 // Exact match requires the number of dots to match (no suffix matching allowed)
9254 bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
9255 necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
9256 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9257 if (domain_matches) {
9258 // No match, matches forbidden domain
9259 return FALSE;
9260 }
9261 } else {
9262 if (!domain_matches) {
9263 // No match, does not match required domain
9264 return FALSE;
9265 }
9266 }
9267 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9268 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
9269 "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
9270 bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
9271 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9272 if (domain_matches) {
9273 // No match, matches forbidden domain
9274 return FALSE;
9275 }
9276 } else {
9277 if (!domain_matches) {
9278 // No match, does not match required domain
9279 return FALSE;
9280 }
9281 }
9282 }
9283
9284 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9285 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9286 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (ID)", kernel_policy->cond_domain_filter, 0);
9287 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9288 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (domain)", "<n/a>", domain.string);
9289 bool domain_matches = false;
9290 if (NECP_IS_DOMAIN_FILTER_ID(kernel_policy->cond_domain_filter)) {
9291 struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
9292 if (filter != NULL && filter->filter != NULL) {
9293 domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
9294 }
9295 } else {
9296 domain_matches = necp_match_domain_with_trie(&necp_global_domain_trie_list, kernel_policy->cond_domain_filter, domain.string, domain.length);
9297 if (debug) {
9298 NECPLOG(LOG_ERR, "DATA-TRACE: matching <%s %zu> with trie id %d - matched %d", domain.string, domain.length, kernel_policy->cond_domain_filter, domain_matches);
9299 }
9300 }
9301 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9302 if (domain_matches) {
9303 // No match, matches forbidden domain
9304 return FALSE;
9305 }
9306 } else {
9307 if (!domain_matches) {
9308 // No match, does not match required domain
9309 return FALSE;
9310 }
9311 }
9312 }
9313
9314 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
9315 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
9316 "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
9317 bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
9318 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
9319 if (url_matches) {
9320 // No match, matches forbidden url
9321 return FALSE;
9322 }
9323 } else {
9324 if (!url_matches) {
9325 // No match, does not match required url
9326 return FALSE;
9327 }
9328 }
9329 }
9330
9331 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9332 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
9333 "NECP_KERNEL_CONDITION_ACCOUNT_ID",
9334 kernel_policy->cond_account_id, account_id);
9335 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9336 if (account_id == kernel_policy->cond_account_id) {
9337 // No match, matches forbidden account
9338 return FALSE;
9339 }
9340 } else {
9341 if (account_id != kernel_policy->cond_account_id) {
9342 // No match, does not match required account
9343 return FALSE;
9344 }
9345 }
9346 }
9347
9348 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
9349 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
9350 "NECP_KERNEL_CONDITION_PID",
9351 kernel_policy->cond_pid, pid);
9352 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
9353 if (pid == kernel_policy->cond_pid) {
9354 // No match, matches forbidden pid
9355 return FALSE;
9356 }
9357 if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
9358 return FALSE;
9359 }
9360 } else {
9361 if (pid != kernel_policy->cond_pid) {
9362 // No match, does not match required pid
9363 return FALSE;
9364 }
9365 if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
9366 return FALSE;
9367 }
9368 }
9369 }
9370
9371 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9372 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9373 "NECP_KERNEL_CONDITION_UID",
9374 kernel_policy->cond_uid, uid);
9375 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9376 if (uid == kernel_policy->cond_uid) {
9377 // No match, matches forbidden uid
9378 return FALSE;
9379 }
9380 } else {
9381 if (uid != kernel_policy->cond_uid) {
9382 // No match, does not match required uid
9383 return FALSE;
9384 }
9385 }
9386 }
9387
9388 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9389 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9390 "NECP_KERNEL_CONDITION_REAL_UID",
9391 kernel_policy->cond_real_uid, real_uid);
9392 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9393 if (real_uid == kernel_policy->cond_real_uid) {
9394 // No match, matches forbidden uid
9395 return FALSE;
9396 }
9397 } else {
9398 if (real_uid != kernel_policy->cond_real_uid) {
9399 // No match, does not match required uid
9400 return FALSE;
9401 }
9402 }
9403 }
9404
9405 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9406 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9407 kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9408 traffic_class, 0, 0);
9409 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9410 if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9411 traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9412 // No match, matches forbidden traffic class
9413 return FALSE;
9414 }
9415 } else {
9416 if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9417 traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9418 // No match, does not match required traffic class
9419 return FALSE;
9420 }
9421 }
9422 }
9423
9424 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9425 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9426 "NECP_KERNEL_CONDITION_PROTOCOL",
9427 kernel_policy->cond_protocol, protocol);
9428 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9429 if (protocol == kernel_policy->cond_protocol) {
9430 // No match, matches forbidden protocol
9431 return FALSE;
9432 }
9433 } else {
9434 if (protocol != kernel_policy->cond_protocol) {
9435 // No match, does not match required protocol
9436 return FALSE;
9437 }
9438 }
9439 }
9440
9441 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9442 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9443 kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9444 "n/a", "n/a", "n/a");
9445 bool matches_agent_type = FALSE;
9446 for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9447 struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9448 if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9449 strbufcmp(required_agent_type->netagent_domain, sizeof(required_agent_type->netagent_domain), kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0) &&
9450 (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9451 strbufcmp(required_agent_type->netagent_type, sizeof(required_agent_type->netagent_type), kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0)) {
9452 // Found a required agent that matches
9453 matches_agent_type = TRUE;
9454 break;
9455 }
9456 }
9457 if (!matches_agent_type) {
9458 return FALSE;
9459 }
9460 }
9461
9462 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9463 bool is_local = FALSE;
9464 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9465
9466 if (rt != NULL) {
9467 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9468 } else {
9469 is_local = necp_is_route_local(remote, include_local_addresses);
9470 }
9471 if (info != NULL) {
9472 info->is_local = is_local;
9473 }
9474
9475 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
9476 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9477 if (is_local) {
9478 // Match local-networks, fail
9479 return FALSE;
9480 }
9481 } else {
9482 if (!is_local) {
9483 // Either no route to validate or no match for local networks
9484 return FALSE;
9485 }
9486 }
9487 }
9488
9489 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9490 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9491 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9492 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9493 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9494 if (inRange) {
9495 return FALSE;
9496 }
9497 } else {
9498 if (!inRange) {
9499 return FALSE;
9500 }
9501 }
9502 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9503 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9504 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
9505 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9506 if (inSubnet) {
9507 return FALSE;
9508 }
9509 } else {
9510 if (!inSubnet) {
9511 return FALSE;
9512 }
9513 }
9514 }
9515 }
9516
9517 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9518 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9519 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9520 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9521 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9522 if (inRange) {
9523 return FALSE;
9524 }
9525 } else {
9526 if (!inRange) {
9527 return FALSE;
9528 }
9529 }
9530 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9531 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9532 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
9533 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9534 if (inSubnet) {
9535 return FALSE;
9536 }
9537 } else {
9538 if (!inSubnet) {
9539 return FALSE;
9540 }
9541 }
9542 }
9543 }
9544
9545 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9546 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9547 "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9548 kernel_policy->cond_client_flags, client_flags);
9549 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9550 if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9551 // Flags do match, and condition is negative, fail.
9552 return FALSE;
9553 }
9554 } else {
9555 if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9556 // Flags do not match, fail.
9557 return FALSE;
9558 }
9559 }
9560 }
9561
9562 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9563 bool isEmpty = necp_addr_is_empty(SA(local));
9564 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9565 "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9566 0, isEmpty);
9567 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9568 if (isEmpty) {
9569 return FALSE;
9570 }
9571 } else {
9572 if (!isEmpty) {
9573 return FALSE;
9574 }
9575 }
9576 }
9577
9578 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9579 bool isEmpty = necp_addr_is_empty(SA(remote));
9580 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9581 "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9582 0, isEmpty);
9583 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9584 if (isEmpty) {
9585 return FALSE;
9586 }
9587 } else {
9588 if (!isEmpty) {
9589 return FALSE;
9590 }
9591 }
9592 }
9593
9594 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9595 u_int16_t remote_port = 0;
9596 if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9597 remote_port = SIN(remote)->sin_port;
9598 }
9599 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9600 "NECP_KERNEL_CONDITION_SCHEME_PORT",
9601 scheme_port, remote_port);
9602 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9603 if (kernel_policy->cond_scheme_port == scheme_port ||
9604 kernel_policy->cond_scheme_port == remote_port) {
9605 return FALSE;
9606 }
9607 } else {
9608 if (kernel_policy->cond_scheme_port != scheme_port &&
9609 kernel_policy->cond_scheme_port != remote_port) {
9610 return FALSE;
9611 }
9612 }
9613 }
9614
9615 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9616 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9617 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9618 kernel_policy->cond_packet_filter_tags,
9619 pf_tag);
9620 bool tags_matched = false;
9621 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9622 if (pf_tag == PF_TAG_ID_STACK_DROP) {
9623 tags_matched = true;
9624 }
9625 }
9626
9627 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9628 if (tags_matched) {
9629 return FALSE;
9630 }
9631 } else {
9632 if (!tags_matched) {
9633 return FALSE;
9634 }
9635 }
9636 }
9637
9638 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9639 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9640 "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9641 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9642 if (is_loopback) {
9643 return FALSE;
9644 }
9645 } else {
9646 if (!is_loopback) {
9647 return FALSE;
9648 }
9649 }
9650 }
9651
9652 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9653 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9654 "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9655 if (is_delegated) {
9656 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9657 if (real_is_platform_binary) {
9658 return FALSE;
9659 }
9660 } else {
9661 if (!real_is_platform_binary) {
9662 return FALSE;
9663 }
9664 }
9665 } else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9666 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9667 // If the connection is not delegated, and the policy did not specify a particular effective process UUID
9668 // or PID, check the process directly
9669 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9670 if (is_platform_binary) {
9671 return FALSE;
9672 }
9673 } else {
9674 if (!is_platform_binary) {
9675 return FALSE;
9676 }
9677 }
9678 }
9679 }
9680
9681 return TRUE;
9682 }
9683
9684 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9685 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9686 {
9687 return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9688 }
9689
9690 static void
necp_socket_fillout_info_locked(struct inpcb * inp,struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,u_int32_t override_bound_interface,soflow_direction_t override_direction,u_int32_t drop_order,proc_t * socket_proc,struct necp_socket_info * info,bool is_loopback,int input_ifindex)9691 necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, soflow_direction_t override_direction, u_int32_t drop_order, proc_t *socket_proc, struct necp_socket_info *info, bool is_loopback, int input_ifindex)
9692 {
9693 struct socket *so = NULL;
9694 proc_t sock_proc = NULL;
9695 proc_t curr_proc = current_proc();
9696
9697 memset(info, 0, sizeof(struct necp_socket_info));
9698
9699 so = inp->inp_socket;
9700
9701 info->drop_order = drop_order;
9702 info->is_loopback = is_loopback;
9703 info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9704
9705 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9706 necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9707 info->uid = kauth_cred_getuid(so->so_cred);
9708 info->real_uid = info->uid;
9709 }
9710
9711 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9712 info->traffic_class = so->so_traffic_class;
9713 }
9714
9715 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9716 info->has_client = !uuid_is_null(inp->necp_client_uuid);
9717 }
9718
9719 if (inp->inp_ip_p) {
9720 info->protocol = inp->inp_ip_p;
9721 } else {
9722 info->protocol = SOCK_PROTO(so);
9723 }
9724
9725 if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9726 u_int32_t responsible_application_id = 0;
9727
9728 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9729 if (existing_mapping) {
9730 info->application_id = existing_mapping->id;
9731 }
9732
9733 #if defined(XNU_TARGET_OS_OSX)
9734 if (so->so_rpid > 0) {
9735 existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9736 if (existing_mapping != NULL) {
9737 responsible_application_id = existing_mapping->id;
9738 }
9739 }
9740 #endif
9741
9742 if (responsible_application_id > 0) {
9743 info->real_application_id = info->application_id;
9744 info->application_id = responsible_application_id;
9745 info->used_responsible_pid = true;
9746 } else if (!(so->so_flags & SOF_DELEGATED)) {
9747 info->real_application_id = info->application_id;
9748 } else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9749 struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9750 if (real_existing_mapping) {
9751 info->real_application_id = real_existing_mapping->id;
9752 }
9753 }
9754 }
9755
9756 pid_t socket_pid =
9757 #if defined(XNU_TARGET_OS_OSX)
9758 info->used_responsible_pid ? so->so_rpid :
9759 #endif
9760 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9761 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9762 sock_proc = proc_find(socket_pid);
9763 if (socket_proc) {
9764 *socket_proc = sock_proc;
9765 }
9766 }
9767
9768 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9769 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9770 info->is_entitled = necp_task_has_match_entitlement(task);
9771 if (!info->is_entitled) {
9772 // Task does not have entitlement, check the parent task
9773 necp_get_parent_is_entitled(task, info);
9774 }
9775 }
9776
9777 info->pid = socket_pid;
9778 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9779 info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9780 }
9781
9782 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9783 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9784 if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9785 info->is_platform_binary = true;
9786 } else if (so->so_rpid != 0) {
9787 proc_t responsible_proc = proc_find(so->so_rpid);
9788 if (responsible_proc != NULL) {
9789 if (necp_is_platform_binary(responsible_proc)) {
9790 info->is_platform_binary = true;
9791 info->used_responsible_pid = true;
9792 }
9793 proc_rele(responsible_proc);
9794 }
9795 }
9796 }
9797
9798 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9799 proc_t real_proc = curr_proc;
9800 bool release_real_proc = false;
9801 if (so->last_pid != proc_pid(real_proc)) {
9802 if (so->last_pid == socket_pid && sock_proc != NULL) {
9803 real_proc = sock_proc;
9804 } else {
9805 proc_t last_proc = proc_find(so->last_pid);
9806 if (last_proc != NULL) {
9807 real_proc = last_proc;
9808 release_real_proc = true;
9809 }
9810 }
9811 }
9812 if (real_proc != NULL) {
9813 if (real_proc == kernproc) {
9814 info->real_is_platform_binary = true;
9815 } else {
9816 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9817 }
9818 if (release_real_proc) {
9819 proc_rele(real_proc);
9820 }
9821 }
9822 }
9823
9824 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9825 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9826 if (existing_mapping) {
9827 info->account_id = existing_mapping->id;
9828 }
9829 }
9830
9831 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9832 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9833 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9834 info->domain = inp->inp_necp_attributes.inp_domain;
9835 }
9836
9837 if (override_bound_interface) {
9838 info->bound_interface_index = override_bound_interface;
9839 } else {
9840 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9841 info->bound_interface_index = inp->inp_boundifp->if_index;
9842 }
9843 }
9844
9845 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9846 info->bound_interface_index != IFSCOPE_NONE) {
9847 ifnet_head_lock_shared();
9848 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9849 if (interface != NULL) {
9850 info->bound_interface_flags = interface->if_flags;
9851 info->bound_interface_eflags = interface->if_eflags;
9852 info->bound_interface_xflags = interface->if_xflags;
9853 }
9854 ifnet_head_done();
9855 }
9856
9857 bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9858 uuid_is_null(inp->necp_client_uuid) &&
9859 necp_socket_has_resolver_signature(inp));
9860 if ((necp_data_tracing_level && necp_data_tracing_port) ||
9861 necp_restrict_multicast ||
9862 needs_address_for_signature ||
9863 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) ||
9864 NEED_DGRAM_FLOW_TRACKING(so)) {
9865 if (override_local_addr != NULL) {
9866 if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9867 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9868 if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9869 struct sockaddr_in sin;
9870 in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9871 memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9872 memcpy(&info->local_addr, &sin, sin.sin_len);
9873 }
9874 } else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9875 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9876 }
9877 } else {
9878 if (inp->inp_vflag & INP_IPV6) {
9879 SIN6(&info->local_addr)->sin6_family = AF_INET6;
9880 SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9881 SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9882 memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9883 } else if (inp->inp_vflag & INP_IPV4) {
9884 SIN(&info->local_addr)->sin_family = AF_INET;
9885 SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9886 SIN(&info->local_addr)->sin_port = inp->inp_lport;
9887 memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9888 }
9889 }
9890
9891 if (override_remote_addr != NULL) {
9892 if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9893 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9894 if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9895 struct sockaddr_in sin;
9896 in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9897 memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9898 memcpy(&info->remote_addr, &sin, sin.sin_len);
9899 }
9900 } else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9901 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9902 }
9903 } else {
9904 if (inp->inp_vflag & INP_IPV6) {
9905 SIN6(&info->remote_addr)->sin6_family = AF_INET6;
9906 SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9907 SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
9908 memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
9909 } else if (inp->inp_vflag & INP_IPV4) {
9910 SIN(&info->remote_addr)->sin_family = AF_INET;
9911 SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9912 SIN(&info->remote_addr)->sin_port = inp->inp_fport;
9913 memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
9914 }
9915 }
9916 // Clear the embedded scope id from v6 addresses
9917 if (info->local_addr.sa.sa_family == AF_INET6) {
9918 struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
9919 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9920 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9921 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9922 sin6->sin6_addr.s6_addr16[1] = 0;
9923 }
9924 }
9925 }
9926 if (info->remote_addr.sa.sa_family == AF_INET6) {
9927 struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
9928 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9929 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9930 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9931 sin6->sin6_addr.s6_addr16[1] = 0;
9932 }
9933 }
9934 }
9935 }
9936
9937 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9938 // For checking sockets, only validate that there is an NECP client present. It will have
9939 // already checked for the signature.
9940 if (!uuid_is_null(inp->necp_client_uuid)) {
9941 info->has_system_signed_result = true;
9942 } else {
9943 info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
9944 }
9945 }
9946
9947 if (NEED_DGRAM_FLOW_TRACKING(so)) {
9948 info->soflow_entry = soflow_get_flow(so, NULL, &(info->remote_addr.sa), NULL, 0, override_direction, input_ifindex);
9949 } else {
9950 info->soflow_entry = NULL;
9951 }
9952
9953 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9954 info->client_flags = 0;
9955 if (INP_NO_CONSTRAINED(inp)) {
9956 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
9957 }
9958 if (INP_NO_EXPENSIVE(inp)) {
9959 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
9960 }
9961 if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
9962 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
9963 }
9964 if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
9965 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
9966 }
9967 if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
9968 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
9969 }
9970 if (NEED_DGRAM_FLOW_TRACKING(so)) {
9971 // If the socket has a flow entry for this 4-tuple then check if the flow is outgoing
9972 // and set the inbound flag accordingly. Otherwise use the direction to set the inbound flag.
9973 if (info->soflow_entry != NULL) {
9974 if (!info->soflow_entry->soflow_outgoing) {
9975 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9976 }
9977 } else if (override_direction == SOFLOW_DIRECTION_INBOUND) {
9978 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9979 }
9980 } else {
9981 // If the socket is explicitly marked as inbound then set the inbound flag.
9982 if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
9983 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9984 }
9985 }
9986 if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
9987 inp->inp_flags2 & INP2_EXTERNAL_PORT) {
9988 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
9989 }
9990 if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
9991 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
9992 }
9993 if (inp->inp_socket->so_options & SO_REUSEPORT) {
9994 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
9995 }
9996 }
9997 }
9998
9999 #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)
10000
10001 static inline struct necp_kernel_socket_policy *
necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,struct necp_socket_info * info,necp_kernel_policy_filter * return_filter,u_int32_t * __counted_by (route_rule_id_array_count)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 * __counted_by (netagent_array_count)return_netagent_array,size_t netagent_array_count,u_int32_t * __counted_by (netagent_use_flags_array_count)return_netagent_use_flags_array,size_t netagent_use_flags_array_count,struct necp_client_parameter_netagent_type * __counted_by (num_required_agent_types)required_agent_types,u_int32_t num_required_agent_types,proc_t proc,u_int16_t pf_tag,necp_kernel_policy_id * skip_policy_id,struct rtentry * rt,necp_kernel_policy_result * return_drop_dest_policy_result,necp_drop_all_bypass_check_result_t * return_drop_all_bypass,u_int32_t * return_flow_divert_aggregate_unit,struct socket * so,int debug)10002 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
10003 struct necp_socket_info *info,
10004 necp_kernel_policy_filter *return_filter,
10005 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
10006 size_t *return_route_rule_id_array_count,
10007 size_t route_rule_id_array_count,
10008 necp_kernel_policy_result *return_service_action,
10009 necp_kernel_policy_service *return_service,
10010 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
10011 size_t netagent_array_count,
10012 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
10013 size_t netagent_use_flags_array_count,
10014 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
10015 u_int32_t num_required_agent_types,
10016 proc_t proc,
10017 u_int16_t pf_tag,
10018 necp_kernel_policy_id *skip_policy_id,
10019 struct rtentry *rt,
10020 necp_kernel_policy_result *return_drop_dest_policy_result,
10021 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
10022 u_int32_t *return_flow_divert_aggregate_unit,
10023 struct socket *so,
10024 int debug)
10025 {
10026 struct necp_kernel_socket_policy *matched_policy = NULL;
10027 u_int32_t skip_order = 0;
10028 u_int32_t skip_session_order = 0;
10029 bool skipped_ip_result = false;
10030 size_t route_rule_id_count = 0;
10031 int i;
10032 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10033 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
10034 memset(&netagent_ids, 0, sizeof(netagent_ids));
10035 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
10036 size_t netagent_cursor = 0;
10037 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10038 size_t netagent_array_count_adjusted = netagent_array_count;
10039 if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
10040 netagent_array_count_adjusted = netagent_use_flags_array_count;
10041 }
10042
10043 if (return_drop_all_bypass != NULL) {
10044 *return_drop_all_bypass = drop_all_bypass;
10045 }
10046
10047 if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
10048 netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
10049 }
10050
10051 // Pre-process domain for quick matching
10052 struct substring domain_substring = {};
10053 u_int8_t domain_dot_count = 0;
10054 if (info->domain != NULL) {
10055 domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
10056 domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
10057 }
10058
10059 if (return_filter != NULL) {
10060 *return_filter = 0;
10061 }
10062
10063 if (return_route_rule_id_array_count != NULL) {
10064 *return_route_rule_id_array_count = 0;
10065 }
10066
10067 if (return_service_action != NULL) {
10068 *return_service_action = 0;
10069 }
10070
10071 if (return_service != NULL) {
10072 return_service->identifier = 0;
10073 return_service->data = 0;
10074 }
10075
10076 // Do not subject layer-2 filter to NECP policies, return a PASS policy
10077 if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
10078 return &pass_policy;
10079 }
10080
10081 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10082
10083 if (policy_search_array != NULL) {
10084 for (i = 0; policy_search_array[i] != NULL; i++) {
10085 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
10086
10087 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10088 // We've hit a drop all rule
10089 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10090 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
10091 if (return_drop_all_bypass != NULL) {
10092 *return_drop_all_bypass = drop_all_bypass;
10093 }
10094 }
10095 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10096 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
10097 break;
10098 }
10099 }
10100 if (necp_drop_dest_policy.entry_count != 0 &&
10101 necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
10102 // We've hit a drop by destination address rule
10103 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10104 break;
10105 }
10106 if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
10107 // We've hit a drop order for this socket
10108 break;
10109 }
10110 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10111 // Done skipping
10112 skip_order = 0;
10113 skip_session_order = 0;
10114 // If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
10115 if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
10116 *skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10117 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
10118 }
10119 }
10120 if (skip_order) {
10121 if (policy_search_array[i]->order < skip_order) {
10122 // Skip this policy
10123 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10124 // didn't, clear out the return value for skip ID when we are done with each session.'
10125 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10126 skipped_ip_result = true;
10127 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10128 }
10129 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
10130 continue;
10131 } else {
10132 // Done skipping
10133 skip_order = 0;
10134 skip_session_order = 0;
10135 }
10136 } else if (skip_session_order) {
10137 // Skip this policy
10138 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10139 // didn't, clear out the return value for skip ID when we are done with each session.'
10140 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10141 skipped_ip_result = true;
10142 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10143 }
10144 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
10145 continue;
10146 }
10147
10148 if (necp_socket_check_policy(policy_search_array[i],
10149 info->application_id,
10150 info->real_application_id,
10151 info->is_entitled,
10152 info->account_id,
10153 domain_substring,
10154 domain_dot_count,
10155 info->url,
10156 info->pid,
10157 info->pid_version,
10158 info->uid,
10159 info->real_uid,
10160 info->bound_interface_index,
10161 info->traffic_class,
10162 info->protocol,
10163 &info->local_addr,
10164 &info->remote_addr,
10165 required_agent_types,
10166 num_required_agent_types,
10167 info->has_client,
10168 info->client_flags,
10169 info->is_platform_binary,
10170 info->has_system_signed_result,
10171 proc,
10172 pf_tag,
10173 info->scheme_port,
10174 rt,
10175 info->is_loopback,
10176 debug,
10177 info->real_is_platform_binary,
10178 info->bound_interface_flags,
10179 info->bound_interface_eflags,
10180 info->bound_interface_xflags,
10181 info,
10182 info->is_delegated,
10183 so)) {
10184 if (!debug && necp_data_tracing_session_order) {
10185 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10186 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10187 NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
10188 }
10189 }
10190
10191 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
10192 if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
10193 necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
10194 if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
10195 *return_filter = control_unit;
10196 } else {
10197 // Preserve pre-existing connections only if all filters preserve.
10198 bool preserve_bit_off = false;
10199 if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
10200 (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
10201 preserve_bit_off = true;
10202 }
10203 *return_filter |= control_unit;
10204 if (preserve_bit_off == true) {
10205 *return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
10206 }
10207 }
10208 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10209 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Filter %d", (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, *return_filter);
10210 }
10211 }
10212 continue;
10213 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10214 if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
10215 return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10216 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10217 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Route Rule %d", (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.route_rule_id);
10218 }
10219 }
10220 continue;
10221 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
10222 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10223 if (netagent_cursor < netagent_array_count_adjusted) {
10224 bool agent_already_present = false;
10225 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10226 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10227 // Already present. Mark the "SCOPED" flag if flags are necessary.
10228 agent_already_present = true;
10229 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
10230 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10231 netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
10232 }
10233 }
10234 }
10235
10236 if (!agent_already_present) {
10237 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10238 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10239 netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
10240 }
10241 netagent_cursor++;
10242 }
10243 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10244 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
10245 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10246 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
10247 policy_search_array[i]->result_parameter.netagent_id);
10248 }
10249 }
10250 continue;
10251 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
10252 bool agent_already_present = false;
10253 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10254 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10255 // Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10256 agent_already_present = true;
10257 netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10258 }
10259 }
10260 if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10261 // If not present, and flags are supported, add an entry with the "REMOVE" flag
10262 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10263 netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10264 netagent_cursor++;
10265 }
10266 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10267 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
10268 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10269 policy_search_array[i]->result_parameter.netagent_id);
10270 }
10271 continue;
10272 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
10273 u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
10274 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
10275 /* For transparent proxies, accumulate the control unit and continue to the next policy */
10276 if (return_flow_divert_aggregate_unit != NULL) {
10277 *return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
10278 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10279 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) flow divert %u", (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, control_unit);
10280 }
10281 }
10282 continue;
10283 }
10284 }
10285
10286 // Matched policy is a skip. Do skip and continue.
10287 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10288 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
10289 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10290 skip_session_order = policy_search_array[i]->session_order + 1;
10291 if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
10292 *skip_policy_id = policy_search_array[i]->id;
10293 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10294 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: MATCHED SKIP POLICY (Application %d Real Application %d BoundInterface %d Proto %d) set skip_policy_id %d", (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, *skip_policy_id);
10295 }
10296 }
10297 continue;
10298 }
10299
10300 // Matched an allow unentitled, which clears any drop order
10301 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
10302 info->drop_order = 0;
10303 continue;
10304 }
10305
10306 // Passed all tests, found a match
10307 matched_policy = policy_search_array[i];
10308 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
10309 break;
10310 }
10311 }
10312 }
10313
10314 if (return_netagent_array != NULL) {
10315 if (return_netagent_use_flags_array != NULL) {
10316 memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
10317 memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
10318 } else {
10319 for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
10320 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
10321 return_netagent_array[netagent_i] = netagent_ids[netagent_i];
10322 } else {
10323 return_netagent_array[netagent_i] = 0;
10324 }
10325 }
10326 }
10327 }
10328
10329 if (return_route_rule_id_array_count != NULL) {
10330 *return_route_rule_id_array_count = route_rule_id_count;
10331 }
10332 return matched_policy;
10333 }
10334
10335 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)10336 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
10337 {
10338 bool found_match = FALSE;
10339 ifaddr_t ifa;
10340 union necp_sockaddr_union address_storage;
10341 int family = AF_INET;
10342
10343 ifnet_head_lock_shared();
10344 ifnet_t interface = ifindex2ifnet[interface_index];
10345 ifnet_head_done();
10346
10347 if (inp == NULL || interface == NULL) {
10348 return FALSE;
10349 }
10350
10351 if (inp->inp_vflag & INP_IPV4) {
10352 family = AF_INET;
10353 } else if (inp->inp_vflag & INP_IPV6) {
10354 family = AF_INET6;
10355 } else {
10356 return FALSE;
10357 }
10358
10359 // Match socket address against interface addresses
10360 ifnet_lock_shared(interface);
10361 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
10362 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
10363 if (address_storage.sa.sa_family != family) {
10364 continue;
10365 }
10366
10367 if (family == AF_INET) {
10368 if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
10369 found_match = TRUE;
10370 break;
10371 }
10372 } else if (family == AF_INET6) {
10373 if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
10374 found_match = TRUE;
10375 break;
10376 }
10377 }
10378 }
10379 }
10380 ifnet_lock_done(interface);
10381
10382 return found_match;
10383 }
10384
10385 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10386 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10387 {
10388 if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10389 proc_t curr_proc = current_proc();
10390 proc_t sock_proc = NULL;
10391 struct socket *so = inp ? inp->inp_socket : NULL;
10392 pid_t socket_pid = (so == NULL) ? 0 :
10393 #if defined(XNU_TARGET_OS_OSX)
10394 so->so_rpid ? so->so_rpid :
10395 #endif
10396 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10397 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10398 sock_proc = proc_find(socket_pid);
10399 }
10400 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10401 if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10402 if (sock_proc) {
10403 proc_rele(sock_proc);
10404 }
10405 return NECP_BYPASS_TYPE_DROP;
10406 }
10407 if (sock_proc) {
10408 proc_rele(sock_proc);
10409 }
10410
10411 if (necp_pass_loopback > 0) {
10412 return NECP_BYPASS_TYPE_LOOPBACK;
10413 }
10414 } else if (necp_is_intcoproc(inp, NULL)) {
10415 return NECP_BYPASS_TYPE_INTCOPROC;
10416 }
10417
10418 return NECP_BYPASS_TYPE_NONE;
10419 }
10420
10421 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10422 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10423 {
10424 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10425 ifnet_t tunnel_interface = NULL;
10426
10427 ifnet_head_lock_shared();
10428 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10429 ifnet_head_done();
10430
10431 if (tunnel_interface != NULL) {
10432 tcp_set_tso(intotcpcb(inp), tunnel_interface);
10433 }
10434 }
10435
10436 static inline void
necp_unscope(struct inpcb * inp)10437 necp_unscope(struct inpcb *inp)
10438 {
10439 // If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10440 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10441 inp->inp_flags &= ~INP_BOUND_IF;
10442 inp->inp_boundifp = NULL;
10443 }
10444 }
10445
10446 static inline void
necp_clear_tunnel(struct inpcb * inp)10447 necp_clear_tunnel(struct inpcb *inp)
10448 {
10449 if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10450 inp->inp_flags &= ~INP_BOUND_IF;
10451 inp->inp_boundifp = NULL;
10452 }
10453 }
10454
10455 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10456 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10457 {
10458 // Verify netagents
10459 for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10460 struct necp_uuid_id_mapping *mapping = NULL;
10461 u_int32_t netagent_id = netagent_ids[netagent_cursor];
10462 if (netagent_id == 0) {
10463 continue;
10464 }
10465 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
10466 if (mapping != NULL) {
10467 u_int32_t agent_flags = 0;
10468 agent_flags = netagent_get_flags(mapping->uuid);
10469 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10470 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10471 continue;
10472 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10473 if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10474 int trigger_error = 0;
10475 trigger_error = netagent_kernel_trigger(mapping->uuid);
10476 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10477 NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> Triggering inactive agent (%d), error %d", (uint64_t)VM_KERNEL_ADDRPERM(so), netagent_id, trigger_error);
10478 }
10479 }
10480 return false;
10481 }
10482 }
10483 }
10484 }
10485 return true;
10486 }
10487
10488 necp_kernel_policy_id
necp_socket_find_policy_match(struct inpcb * inp,struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,u_int32_t override_bound_interface)10489 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10490 {
10491 struct socket *so = NULL;
10492 necp_kernel_policy_filter filter_control_unit = 0;
10493 struct necp_kernel_socket_policy *matched_policy = NULL;
10494 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10495 necp_kernel_policy_result service_action = 0;
10496 necp_kernel_policy_service service = { 0, 0 };
10497 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10498 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10499 proc_t __single socket_proc = NULL;
10500 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10501
10502 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10503 memset(&netagent_ids, 0, sizeof(netagent_ids));
10504
10505 struct necp_socket_info info = {};
10506
10507 u_int32_t flow_divert_aggregate_unit = 0;
10508
10509 if (inp == NULL) {
10510 return NECP_KERNEL_POLICY_ID_NONE;
10511 }
10512
10513 // Ignore invalid addresses
10514 if (override_local_addr != NULL &&
10515 !necp_address_is_valid(override_local_addr)) {
10516 override_local_addr = NULL;
10517 }
10518 if (override_remote_addr != NULL &&
10519 !necp_address_is_valid(override_remote_addr)) {
10520 override_remote_addr = NULL;
10521 }
10522
10523 so = inp->inp_socket;
10524
10525 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10526
10527 // Don't lock. Possible race condition, but we don't want the performance hit.
10528 if (necp_drop_management_order == 0 &&
10529 (necp_kernel_socket_policies_count == 0 ||
10530 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10531 if (necp_drop_all_order > 0 || drop_order > 0) {
10532 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10533 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10534 inp->inp_policyresult.policy_gencount = 0;
10535 inp->inp_policyresult.app_id = 0;
10536 inp->inp_policyresult.flowhash = 0;
10537 inp->inp_policyresult.results.filter_control_unit = 0;
10538 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10539 inp->inp_policyresult.results.route_rule_id = 0;
10540 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10541 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10542 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10543 } else {
10544 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10545 }
10546 }
10547 return NECP_KERNEL_POLICY_ID_NONE;
10548 }
10549
10550 // Check for loopback exception
10551 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10552 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10553 // Mark socket as a drop
10554 necp_unscope(inp);
10555 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10556 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10557 inp->inp_policyresult.policy_gencount = 0;
10558 inp->inp_policyresult.app_id = 0;
10559 inp->inp_policyresult.flowhash = 0;
10560 inp->inp_policyresult.results.filter_control_unit = 0;
10561 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10562 inp->inp_policyresult.results.route_rule_id = 0;
10563 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10564 return NECP_KERNEL_POLICY_ID_NONE;
10565 }
10566
10567 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10568 // Mark socket as a pass
10569 necp_unscope(inp);
10570 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10571 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10572 inp->inp_policyresult.policy_gencount = 0;
10573 inp->inp_policyresult.app_id = 0;
10574 inp->inp_policyresult.flowhash = 0;
10575 inp->inp_policyresult.results.filter_control_unit = 0;
10576 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10577 inp->inp_policyresult.results.route_rule_id = 0;
10578 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10579 return NECP_KERNEL_POLICY_ID_NONE;
10580 }
10581
10582 // Lock
10583 lck_rw_lock_shared(&necp_kernel_policy_lock);
10584 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, SOFLOW_DIRECTION_UNKNOWN, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), 0);
10585
10586 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10587 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10588
10589 // Check info
10590 u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10591 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10592 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10593 inp->inp_policyresult.flowhash == flowhash) {
10594 // If already matched this socket on this generation of table, skip
10595
10596 if (info.soflow_entry != NULL) {
10597 soflow_free_flow(info.soflow_entry);
10598 }
10599
10600 // Unlock
10601 lck_rw_done(&necp_kernel_policy_lock);
10602
10603 if (socket_proc) {
10604 proc_rele(socket_proc);
10605 }
10606
10607 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10608 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10609 inp->inp_socket, info.bound_interface_index, info.protocol,
10610 inp->inp_policyresult.policy_id,
10611 inp->inp_policyresult.results.result,
10612 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10613 }
10614 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10615 return inp->inp_policyresult.policy_id;
10616 }
10617
10618 inp->inp_policyresult.app_id = info.application_id;
10619
10620 // Match socket to policy
10621 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10622 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10623 size_t route_rule_id_array_count = 0;
10624
10625 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10626 matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
10627 &info,
10628 &filter_control_unit,
10629 route_rule_id_array,
10630 &route_rule_id_array_count,
10631 MAX_AGGREGATE_ROUTE_RULES,
10632 &service_action,
10633 &service,
10634 netagent_ids,
10635 NECP_MAX_NETAGENTS,
10636 NULL,
10637 0,
10638 NULL,
10639 0,
10640 effective_proc,
10641 0,
10642 &skip_policy_id,
10643 inp->inp_route.ro_rt,
10644 &drop_dest_policy_result,
10645 &drop_all_bypass,
10646 &flow_divert_aggregate_unit,
10647 so,
10648 debug);
10649
10650 // Check for loopback exception again after the policy match
10651 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10652 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10653 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10654 // Mark socket as a pass
10655 necp_unscope(inp);
10656 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10657 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10658 inp->inp_policyresult.policy_gencount = 0;
10659 inp->inp_policyresult.app_id = 0;
10660 inp->inp_policyresult.flowhash = 0;
10661 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10662 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10663 inp->inp_policyresult.results.route_rule_id = 0;
10664 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10665 if (info.soflow_entry != NULL) {
10666 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10667 info.soflow_entry->soflow_policies_gencount = 0;
10668 soflow_free_flow(info.soflow_entry);
10669 }
10670
10671 // Unlock
10672 lck_rw_done(&necp_kernel_policy_lock);
10673
10674 if (socket_proc) {
10675 proc_rele(socket_proc);
10676 }
10677
10678 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10679 return NECP_KERNEL_POLICY_ID_NONE;
10680 }
10681
10682 // Verify netagents
10683 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10684 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10685 NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Dropping packet because agent is not active", (uint64_t)VM_KERNEL_ADDRPERM(so), info.bound_interface_index, info.protocol);
10686 }
10687
10688 // Mark socket as a drop if required agent is not active
10689 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10690 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10691 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10692 inp->inp_policyresult.flowhash = flowhash;
10693 inp->inp_policyresult.results.filter_control_unit = 0;
10694 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10695 inp->inp_policyresult.results.route_rule_id = 0;
10696 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10697 if (info.soflow_entry != NULL) {
10698 info.soflow_entry->soflow_filter_control_unit = 0;
10699 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10700 soflow_free_flow(info.soflow_entry);
10701 }
10702
10703 // Unlock
10704 lck_rw_done(&necp_kernel_policy_lock);
10705
10706 if (socket_proc) {
10707 proc_rele(socket_proc);
10708 }
10709
10710 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Inactive Agent DROP", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10711 return NECP_KERNEL_POLICY_ID_NONE;
10712 }
10713
10714 u_int32_t route_rule_id = 0;
10715 if (route_rule_id_array_count == 1) {
10716 route_rule_id = route_rule_id_array[0];
10717 } else if (route_rule_id_array_count > 1) {
10718 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10719 }
10720
10721 bool reset_tcp_tunnel_interface = false;
10722 bool send_local_network_denied_event = false;
10723 if (matched_policy) {
10724 // For PASS policy result, clear previous rescope / tunnel inteface
10725 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10726 (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10727 necp_unscope(inp);
10728 necp_clear_tunnel(inp);
10729 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10730 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10731 }
10732 }
10733 matched_policy_id = matched_policy->id;
10734 inp->inp_policyresult.policy_id = matched_policy->id;
10735 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10736 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10737 inp->inp_policyresult.flowhash = flowhash;
10738 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10739 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10740 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10741 inp->inp_policyresult.results.result = matched_policy->result;
10742 memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10743 if (info.soflow_entry != NULL) {
10744 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10745 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10746 }
10747
10748 if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10749 inp->inp_policyresult.app_id = info.real_application_id;
10750 }
10751
10752 if (necp_socket_is_connected(inp) &&
10753 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10754 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10755 NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10756 sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10757 } else if (necp_socket_is_connected(inp) &&
10758 matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10759 info.protocol == IPPROTO_TCP) {
10760 // Reset TCP socket interface based parameters if tunnel policy changes
10761 reset_tcp_tunnel_interface = true;
10762 }
10763
10764 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10765 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Policy %d Skip %d Result %d Parameter %d Filter %d", (uint64_t)VM_KERNEL_ADDRPERM(so), info.bound_interface_index, info.protocol, matched_policy->id, skip_policy_id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index, inp->inp_policyresult.results.filter_control_unit);
10766 }
10767
10768 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10769 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10770 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10771 // Trigger the event that we dropped due to a local network policy
10772 send_local_network_denied_event = true;
10773 }
10774 } else {
10775 bool drop_all = false;
10776 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10777 // Mark socket as a drop if set
10778 drop_all = true;
10779 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10780 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10781 }
10782 }
10783
10784 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10785 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(NULL, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &flow_divert_aggregate_unit);
10786 if (flow_divert_control_unit != 0) {
10787 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10788 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10789 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10790 inp->inp_policyresult.flowhash = flowhash;
10791 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10792 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10793 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10794 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10795 inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10796 if (info.soflow_entry != NULL) {
10797 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10798 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10799 }
10800 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "FLOW DIVERT <ROUTE RULE>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10801 } else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10802 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10803 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10804 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10805 inp->inp_policyresult.flowhash = flowhash;
10806 inp->inp_policyresult.results.filter_control_unit = 0;
10807 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10808 inp->inp_policyresult.results.route_rule_id = 0;
10809 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10810 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <NO MATCH>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10811 if (info.soflow_entry != NULL) {
10812 info.soflow_entry->soflow_filter_control_unit = 0;
10813 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10814 }
10815 } else {
10816 // Mark non-matching socket so we don't re-check it
10817 necp_unscope(inp);
10818 if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10819 necp_clear_tunnel(inp);
10820 }
10821 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10822 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for <NO MATCH>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10823 }
10824 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10825 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10826 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10827 inp->inp_policyresult.flowhash = flowhash;
10828 inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10829 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10830 inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10831 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10832 if (info.soflow_entry != NULL) {
10833 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10834 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10835 }
10836 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10837 }
10838 }
10839
10840 if (necp_check_missing_client_drop(effective_proc, &info) ||
10841 necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10842 // Mark as drop
10843 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10844 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10845 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10846 inp->inp_policyresult.flowhash = flowhash;
10847 inp->inp_policyresult.results.filter_control_unit = 0;
10848 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10849 inp->inp_policyresult.results.route_rule_id = 0;
10850 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10851 if (info.soflow_entry != NULL) {
10852 info.soflow_entry->soflow_filter_control_unit = 0;
10853 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10854 }
10855 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10856 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10857 }
10858 }
10859
10860 if (info.soflow_entry != NULL) {
10861 soflow_free_flow(info.soflow_entry);
10862 }
10863
10864 // Unlock
10865 lck_rw_done(&necp_kernel_policy_lock);
10866
10867 if (reset_tcp_tunnel_interface) {
10868 // Update MSS when not holding the policy lock to avoid recursive locking
10869 tcp_mtudisc(inp, 0);
10870
10871 // Update TSO flag based on the tunnel interface
10872 necp_socket_ip_tunnel_tso(inp);
10873 }
10874
10875 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10876 inp->inp_policyresult.network_denied_notifies++;
10877 #if defined(XNU_TARGET_OS_OSX)
10878 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10879 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10880 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10881 NETPOLICY_NETWORKTYPE_LOCAL);
10882 #else
10883 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10884 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10885 NETPOLICY_NETWORKTYPE_LOCAL);
10886 #endif
10887 }
10888
10889 if (socket_proc) {
10890 proc_rele(socket_proc);
10891 }
10892
10893 return matched_policy_id;
10894 }
10895
10896 static bool
necp_ip_output_check_policy(struct necp_kernel_ip_output_policy * kernel_policy,necp_kernel_policy_id socket_policy_id,necp_kernel_policy_id socket_skip_policy_id,u_int32_t bound_interface_index,u_int32_t last_interface_index,u_int16_t protocol,union necp_sockaddr_union * local,union necp_sockaddr_union * remote,struct rtentry * rt,u_int16_t pf_tag,int debug)10897 necp_ip_output_check_policy(struct necp_kernel_ip_output_policy *kernel_policy, necp_kernel_policy_id socket_policy_id, necp_kernel_policy_id socket_skip_policy_id, u_int32_t bound_interface_index, u_int32_t last_interface_index, u_int16_t protocol, union necp_sockaddr_union *local, union necp_sockaddr_union *remote, struct rtentry *rt, u_int16_t pf_tag, int debug)
10898 {
10899 u_int32_t bound_interface_flags = 0;
10900 u_int32_t bound_interface_eflags = 0;
10901 u_int32_t bound_interface_xflags = 0;
10902
10903 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
10904 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10905 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
10906 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
10907 "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
10908 cond_bound_interface_index, bound_interface_index);
10909 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10910 if (bound_interface_index == cond_bound_interface_index) {
10911 // No match, matches forbidden interface
10912 return FALSE;
10913 }
10914 } else {
10915 if (bound_interface_index != cond_bound_interface_index) {
10916 // No match, does not match required interface
10917 return FALSE;
10918 }
10919 }
10920 }
10921 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10922 if (bound_interface_index != IFSCOPE_NONE) {
10923 ifnet_head_lock_shared();
10924 ifnet_t interface = ifindex2ifnet[bound_interface_index];
10925 if (interface != NULL) {
10926 bound_interface_flags = interface->if_flags;
10927 bound_interface_eflags = interface->if_eflags;
10928 bound_interface_xflags = interface->if_xflags;
10929 }
10930 ifnet_head_done();
10931 }
10932
10933 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10934 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
10935 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10936 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
10937 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10938 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
10939 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10940 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10941 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10942 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10943 // No match, matches some forbidden interface flags
10944 return FALSE;
10945 }
10946 } else {
10947 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10948 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10949 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10950 // No match, does not match some required interface xflags
10951 return FALSE;
10952 }
10953 }
10954 }
10955 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
10956 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
10957 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
10958 if (bound_interface_index != 0) {
10959 // No match, requires a non-bound packet
10960 return FALSE;
10961 }
10962 }
10963 }
10964
10965 if (kernel_policy->condition_mask == 0) {
10966 return TRUE;
10967 }
10968
10969 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10970 necp_kernel_policy_id matched_policy_id =
10971 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10972 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
10973 "NECP_KERNEL_CONDITION_POLICY_ID",
10974 kernel_policy->cond_policy_id, 0, 0,
10975 matched_policy_id, socket_policy_id, socket_skip_policy_id);
10976 if (matched_policy_id != kernel_policy->cond_policy_id) {
10977 // No match, does not match required id
10978 return FALSE;
10979 }
10980 }
10981
10982 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10983 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
10984 "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10985 kernel_policy->cond_last_interface_index, last_interface_index);
10986 if (last_interface_index != kernel_policy->cond_last_interface_index) {
10987 return FALSE;
10988 }
10989 }
10990
10991 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10992 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
10993 "NECP_KERNEL_CONDITION_PROTOCOL",
10994 kernel_policy->cond_protocol, protocol);
10995 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10996 if (protocol == kernel_policy->cond_protocol) {
10997 // No match, matches forbidden protocol
10998 return FALSE;
10999 }
11000 } else {
11001 if (protocol != kernel_policy->cond_protocol) {
11002 // No match, does not match required protocol
11003 return FALSE;
11004 }
11005 }
11006 }
11007
11008 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11009 bool is_local = FALSE;
11010 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
11011
11012 if (rt != NULL) {
11013 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
11014 } else {
11015 is_local = necp_is_route_local(remote, include_local_addresses);
11016 }
11017 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
11018 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11019 if (is_local) {
11020 // Match local-networks, fail
11021 return FALSE;
11022 }
11023 } else {
11024 if (!is_local) {
11025 // Either no route to validate or no match for local networks
11026 return FALSE;
11027 }
11028 }
11029 }
11030
11031 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
11032 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11033 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
11034 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
11035 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11036 if (inRange) {
11037 return FALSE;
11038 }
11039 } else {
11040 if (!inRange) {
11041 return FALSE;
11042 }
11043 }
11044 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11045 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
11046 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
11047 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11048 if (inSubnet) {
11049 return FALSE;
11050 }
11051 } else {
11052 if (!inSubnet) {
11053 return FALSE;
11054 }
11055 }
11056 }
11057 }
11058
11059 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
11060 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11061 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
11062 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
11063 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11064 if (inRange) {
11065 return FALSE;
11066 }
11067 } else {
11068 if (!inRange) {
11069 return FALSE;
11070 }
11071 }
11072 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11073 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
11074 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
11075 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11076 if (inSubnet) {
11077 return FALSE;
11078 }
11079 } else {
11080 if (!inSubnet) {
11081 return FALSE;
11082 }
11083 }
11084 }
11085 }
11086
11087 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11088 u_int16_t remote_port = 0;
11089 if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
11090 remote_port = SIN(remote)->sin_port;
11091 }
11092 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
11093 "NECP_KERNEL_CONDITION_SCHEME_PORT",
11094 0, remote_port);
11095 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11096 if (kernel_policy->cond_scheme_port == remote_port) {
11097 return FALSE;
11098 }
11099 } else {
11100 if (kernel_policy->cond_scheme_port != remote_port) {
11101 return FALSE;
11102 }
11103 }
11104 }
11105
11106 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11107 bool tags_matched = false;
11108 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
11109 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
11110 kernel_policy->cond_packet_filter_tags, pf_tag);
11111 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
11112 if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
11113 tags_matched = true;
11114 }
11115
11116 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11117 if (tags_matched) {
11118 return FALSE;
11119 }
11120 } else {
11121 if (!tags_matched) {
11122 return FALSE;
11123 }
11124 }
11125 }
11126 }
11127
11128 return TRUE;
11129 }
11130
11131 static inline struct necp_kernel_ip_output_policy *
necp_ip_output_find_policy_match_locked(necp_kernel_policy_id socket_policy_id,necp_kernel_policy_id socket_skip_policy_id,u_int32_t bound_interface_index,u_int32_t last_interface_index,u_int16_t protocol,union necp_sockaddr_union * local_addr,union necp_sockaddr_union * remote_addr,struct rtentry * rt,u_int16_t pf_tag,u_int32_t * return_route_rule_id,necp_kernel_policy_result * return_drop_dest_policy_result,necp_drop_all_bypass_check_result_t * return_drop_all_bypass,int debug)11132 necp_ip_output_find_policy_match_locked(necp_kernel_policy_id socket_policy_id, necp_kernel_policy_id socket_skip_policy_id, u_int32_t bound_interface_index, u_int32_t last_interface_index, u_int16_t protocol, union necp_sockaddr_union *local_addr, union necp_sockaddr_union *remote_addr, struct rtentry *rt, u_int16_t pf_tag, u_int32_t *return_route_rule_id, necp_kernel_policy_result *return_drop_dest_policy_result, necp_drop_all_bypass_check_result_t *return_drop_all_bypass, int debug)
11133 {
11134 u_int32_t skip_order = 0;
11135 u_int32_t skip_session_order = 0;
11136 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11137 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)];
11138 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11139 size_t route_rule_id_count = 0;
11140 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11141 if (return_drop_all_bypass != NULL) {
11142 *return_drop_all_bypass = drop_all_bypass;
11143 }
11144
11145 if (return_route_rule_id != NULL) {
11146 *return_route_rule_id = 0;
11147 }
11148
11149 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11150
11151 if (policy_search_array != NULL) {
11152 for (int i = 0; policy_search_array[i] != NULL; i++) {
11153 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
11154 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
11155 // We've hit a drop all rule
11156 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11157 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11158 if (return_drop_all_bypass != NULL) {
11159 *return_drop_all_bypass = drop_all_bypass;
11160 }
11161 }
11162 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11163 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
11164 break;
11165 }
11166 }
11167 if (necp_drop_dest_policy.entry_count > 0 &&
11168 necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
11169 // We've hit a drop by destination address rule
11170 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
11171 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
11172 break;
11173 }
11174 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
11175 // Done skipping
11176 skip_order = 0;
11177 skip_session_order = 0;
11178 }
11179 if (skip_order) {
11180 if (policy_search_array[i]->order < skip_order) {
11181 // Skip this policy
11182 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
11183 continue;
11184 } else {
11185 // Done skipping
11186 skip_order = 0;
11187 skip_session_order = 0;
11188 }
11189 } else if (skip_session_order) {
11190 // Skip this policy
11191 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
11192 continue;
11193 }
11194
11195 if (necp_ip_output_check_policy(policy_search_array[i], socket_policy_id, socket_skip_policy_id, bound_interface_index, last_interface_index, protocol, local_addr, remote_addr, rt, pf_tag, debug)) {
11196 if (!debug && necp_data_tracing_session_order) {
11197 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
11198 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
11199 NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
11200 }
11201 }
11202
11203 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
11204 if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
11205 route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
11206 }
11207 continue;
11208 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
11209 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
11210 skip_session_order = policy_search_array[i]->session_order + 1;
11211 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
11212 continue;
11213 }
11214
11215 // Passed all tests, found a match
11216 matched_policy = policy_search_array[i];
11217 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
11218 break;
11219 }
11220 }
11221 }
11222
11223 if (route_rule_id_count == 1) {
11224 *return_route_rule_id = route_rule_id_array[0];
11225 } else if (route_rule_id_count > 1) {
11226 *return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11227 }
11228
11229 return matched_policy;
11230 }
11231
11232 static inline bool
necp_output_bypass(struct mbuf * packet)11233 necp_output_bypass(struct mbuf *packet)
11234 {
11235 if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
11236 return true;
11237 }
11238 if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
11239 return true;
11240 }
11241 if (necp_is_intcoproc(NULL, packet)) {
11242 return true;
11243 }
11244 return false;
11245 }
11246
11247 necp_kernel_policy_id
necp_ip_output_find_policy_match(struct mbuf * packet,int flags,struct ip_out_args * ipoa,struct rtentry * rt,necp_kernel_policy_result * result,necp_kernel_policy_result_parameter * result_parameter)11248 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
11249 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11250 {
11251 struct ip *ip = NULL;
11252 int hlen = sizeof(struct ip);
11253 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11254 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11255 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11256 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11257 u_int16_t protocol = 0;
11258 u_int32_t bound_interface_index = 0;
11259 u_int32_t last_interface_index = 0;
11260 union necp_sockaddr_union local_addr = { };
11261 union necp_sockaddr_union remote_addr = { };
11262 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11263 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11264 u_int16_t pf_tag = 0;
11265
11266 if (result) {
11267 *result = 0;
11268 }
11269
11270 if (result_parameter) {
11271 memset(result_parameter, 0, sizeof(*result_parameter));
11272 }
11273
11274 if (packet == NULL) {
11275 return NECP_KERNEL_POLICY_ID_NONE;
11276 }
11277
11278 socket_policy_id = necp_get_policy_id_from_packet(packet);
11279 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11280 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11281
11282 // Exit early for an empty list
11283 // Don't lock. Possible race condition, but we don't want the performance hit.
11284 if (necp_kernel_ip_output_policies_count == 0 ||
11285 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
11286 if (necp_drop_all_order > 0) {
11287 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11288 if (result) {
11289 if (necp_output_bypass(packet)) {
11290 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11291 } else {
11292 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11293 }
11294 }
11295 }
11296
11297 return matched_policy_id;
11298 }
11299
11300 // Check for loopback exception
11301 if (necp_output_bypass(packet)) {
11302 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11303 if (result) {
11304 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11305 }
11306 return matched_policy_id;
11307 }
11308
11309 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11310
11311 // Process packet to get relevant fields
11312 ip = mtod(packet, struct ip *);
11313 #ifdef _IP_VHL
11314 hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
11315 #else
11316 hlen = ip->ip_hl << 2;
11317 #endif
11318
11319 protocol = ip->ip_p;
11320
11321 if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
11322 (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
11323 ipoa->ipoa_boundif != IFSCOPE_NONE) {
11324 bound_interface_index = ipoa->ipoa_boundif;
11325 }
11326
11327 local_addr.sin.sin_family = AF_INET;
11328 local_addr.sin.sin_len = sizeof(struct sockaddr_in);
11329 memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
11330
11331 remote_addr.sin.sin_family = AF_INET;
11332 remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
11333 memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
11334
11335 switch (protocol) {
11336 case IPPROTO_TCP: {
11337 struct tcphdr th;
11338 if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
11339 m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
11340 SIN(&local_addr)->sin_port = th.th_sport;
11341 SIN(&remote_addr)->sin_port = th.th_dport;
11342 }
11343 break;
11344 }
11345 case IPPROTO_UDP: {
11346 struct udphdr uh;
11347 if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
11348 m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
11349 SIN(&local_addr)->sin_port = uh.uh_sport;
11350 SIN(&remote_addr)->sin_port = uh.uh_dport;
11351 }
11352 break;
11353 }
11354 default: {
11355 SIN(&local_addr)->sin_port = 0;
11356 SIN(&remote_addr)->sin_port = 0;
11357 break;
11358 }
11359 }
11360
11361 // Match packet to policy
11362 lck_rw_lock_shared(&necp_kernel_policy_lock);
11363 u_int32_t route_rule_id = 0;
11364
11365 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11366 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
11367
11368 matched_policy = necp_ip_output_find_policy_match_locked(socket_policy_id, socket_skip_policy_id, bound_interface_index, last_interface_index, protocol, &local_addr, &remote_addr, rt, pf_tag, &route_rule_id, &drop_dest_policy_result, &drop_all_bypass, debug);
11369 if (matched_policy) {
11370 matched_policy_id = matched_policy->id;
11371 if (result) {
11372 *result = matched_policy->result;
11373 }
11374
11375 if (result_parameter) {
11376 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11377 }
11378
11379 if (route_rule_id != 0 &&
11380 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11381 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11382 }
11383
11384 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11385 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);
11386 }
11387 } else {
11388 bool drop_all = false;
11389 /*
11390 * Apply drop-all only to packets which have never matched a primary policy (check
11391 * if the packet saved policy id is none or falls within the socket policy id range).
11392 */
11393 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11394 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11395 drop_all = true;
11396 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11397 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11398 }
11399 }
11400 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11401 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11402 if (result) {
11403 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11404 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
11405 }
11406 } else if (route_rule_id != 0 &&
11407 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11408 // If we matched a route rule, mark it
11409 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11410 }
11411 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11412 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);
11413 }
11414 }
11415
11416 lck_rw_done(&necp_kernel_policy_lock);
11417
11418 return matched_policy_id;
11419 }
11420
11421 necp_kernel_policy_id
necp_ip6_output_find_policy_match(struct mbuf * packet,int flags,struct ip6_out_args * ip6oa,struct rtentry * rt,necp_kernel_policy_result * result,necp_kernel_policy_result_parameter * result_parameter)11422 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11423 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11424 {
11425 struct ip6_hdr *ip6 = NULL;
11426 int next = -1;
11427 int offset = 0;
11428 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11429 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11430 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11431 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11432 u_int16_t protocol = 0;
11433 u_int32_t bound_interface_index = 0;
11434 u_int32_t last_interface_index = 0;
11435 union necp_sockaddr_union local_addr = { };
11436 union necp_sockaddr_union remote_addr = { };
11437 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11438 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11439 u_int16_t pf_tag = 0;
11440
11441 if (result) {
11442 *result = 0;
11443 }
11444
11445 if (result_parameter) {
11446 memset(result_parameter, 0, sizeof(*result_parameter));
11447 }
11448
11449 if (packet == NULL) {
11450 return NECP_KERNEL_POLICY_ID_NONE;
11451 }
11452
11453 socket_policy_id = necp_get_policy_id_from_packet(packet);
11454 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11455 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11456
11457 // Exit early for an empty list
11458 // Don't lock. Possible race condition, but we don't want the performance hit.
11459 if (necp_drop_management_order == 0 &&
11460 (necp_kernel_ip_output_policies_count == 0 ||
11461 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11462 if (necp_drop_all_order > 0) {
11463 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11464 if (result) {
11465 if (necp_output_bypass(packet)) {
11466 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11467 } else {
11468 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11469 }
11470 }
11471 }
11472
11473 return matched_policy_id;
11474 }
11475
11476 // Check for loopback exception
11477 if (necp_output_bypass(packet)) {
11478 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11479 if (result) {
11480 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11481 }
11482 return matched_policy_id;
11483 }
11484
11485 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11486
11487 // Process packet to get relevant fields
11488 ip6 = mtod(packet, struct ip6_hdr *);
11489
11490 if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11491 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11492 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11493 bound_interface_index = ip6oa->ip6oa_boundif;
11494 }
11495
11496 SIN6(&local_addr)->sin6_family = AF_INET6;
11497 SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11498 memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11499
11500 SIN6(&remote_addr)->sin6_family = AF_INET6;
11501 SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11502 memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11503
11504 offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11505 if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11506 protocol = next;
11507 switch (protocol) {
11508 case IPPROTO_TCP: {
11509 struct tcphdr th;
11510 if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11511 m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11512 SIN6(&local_addr)->sin6_port = th.th_sport;
11513 SIN6(&remote_addr)->sin6_port = th.th_dport;
11514 }
11515 break;
11516 }
11517 case IPPROTO_UDP: {
11518 struct udphdr uh;
11519 if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11520 m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11521 SIN6(&local_addr)->sin6_port = uh.uh_sport;
11522 SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11523 }
11524 break;
11525 }
11526 default: {
11527 SIN6(&local_addr)->sin6_port = 0;
11528 SIN6(&remote_addr)->sin6_port = 0;
11529 break;
11530 }
11531 }
11532 }
11533
11534 // Match packet to policy
11535 lck_rw_lock_shared(&necp_kernel_policy_lock);
11536 u_int32_t route_rule_id = 0;
11537
11538 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11539 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11540
11541 matched_policy = necp_ip_output_find_policy_match_locked(socket_policy_id, socket_skip_policy_id, bound_interface_index, last_interface_index, protocol, &local_addr, &remote_addr, rt, pf_tag, &route_rule_id, &drop_dest_policy_result, &drop_all_bypass, debug);
11542 if (matched_policy) {
11543 matched_policy_id = matched_policy->id;
11544 if (result) {
11545 *result = matched_policy->result;
11546 }
11547
11548 if (result_parameter) {
11549 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11550 }
11551
11552 if (route_rule_id != 0 &&
11553 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11554 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11555 }
11556
11557 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11558 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);
11559 }
11560 } else {
11561 bool drop_all = false;
11562 /*
11563 * Apply drop-all only to packets which have never matched a primary policy (check
11564 * if the packet saved policy id is none or falls within the socket policy id range).
11565 */
11566 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11567 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11568 drop_all = true;
11569 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11570 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11571 }
11572 }
11573 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11574 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11575 if (result) {
11576 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11577 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11578 }
11579 } else if (route_rule_id != 0 &&
11580 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11581 // If we matched a route rule, mark it
11582 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11583 }
11584 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11585 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);
11586 }
11587 }
11588
11589 lck_rw_done(&necp_kernel_policy_lock);
11590
11591 return matched_policy_id;
11592 }
11593
11594 // Utilities
11595 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11596 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11597 {
11598 int cmp = 0;
11599
11600 if (addr == NULL || range_start == NULL || range_end == NULL) {
11601 return FALSE;
11602 }
11603
11604 /* Must be greater than or equal to start */
11605 cmp = necp_addr_compare(addr, range_start, 1);
11606 if (cmp != 0 && cmp != 1) {
11607 return FALSE;
11608 }
11609
11610 /* Must be less than or equal to end */
11611 cmp = necp_addr_compare(addr, range_end, 1);
11612 if (cmp != 0 && cmp != -1) {
11613 return FALSE;
11614 }
11615
11616 return TRUE;
11617 }
11618
11619 static bool
necp_is_range_in_range(struct sockaddr * inner_range_start,struct sockaddr * inner_range_end,struct sockaddr * range_start,struct sockaddr * range_end)11620 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11621 {
11622 int cmp = 0;
11623
11624 if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11625 return FALSE;
11626 }
11627
11628 /* Must be greater than or equal to start */
11629 cmp = necp_addr_compare(inner_range_start, range_start, 1);
11630 if (cmp != 0 && cmp != 1) {
11631 return FALSE;
11632 }
11633
11634 /* Must be less than or equal to end */
11635 cmp = necp_addr_compare(inner_range_end, range_end, 1);
11636 if (cmp != 0 && cmp != -1) {
11637 return FALSE;
11638 }
11639
11640 return TRUE;
11641 }
11642
11643 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11644 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11645 {
11646 if (addr == NULL || subnet_addr == NULL) {
11647 return FALSE;
11648 }
11649
11650 if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11651 return FALSE;
11652 }
11653
11654 switch (addr->sa_family) {
11655 case AF_INET: {
11656 if (satosin(subnet_addr)->sin_port != 0 &&
11657 satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11658 return FALSE;
11659 }
11660 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11661 }
11662 case AF_INET6: {
11663 if (satosin6(subnet_addr)->sin6_port != 0 &&
11664 satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11665 return FALSE;
11666 }
11667 if (satosin6(addr)->sin6_scope_id &&
11668 satosin6(subnet_addr)->sin6_scope_id &&
11669 satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11670 return FALSE;
11671 }
11672 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11673 }
11674 default: {
11675 return FALSE;
11676 }
11677 }
11678
11679 return FALSE;
11680 }
11681
11682 /*
11683 * Return values:
11684 * -1: sa1 < sa2
11685 * 0: sa1 == sa2
11686 * 1: sa1 > sa2
11687 * 2: Not comparable or error
11688 */
11689 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11690 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11691 {
11692 int result = 0;
11693 int port_result = 0;
11694
11695 if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11696 return 2;
11697 }
11698
11699 if (sa1->sa_len == 0) {
11700 return 0;
11701 }
11702
11703 switch (sa1->sa_family) {
11704 case AF_INET: {
11705 if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11706 return 2;
11707 }
11708
11709 result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11710
11711 if (check_port) {
11712 if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11713 port_result = -1;
11714 } else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11715 port_result = 1;
11716 }
11717
11718 if (result == 0) {
11719 result = port_result;
11720 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11721 return 2;
11722 }
11723 }
11724
11725 break;
11726 }
11727 case AF_INET6: {
11728 if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11729 return 2;
11730 }
11731
11732 if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11733 return 2;
11734 }
11735
11736 result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11737
11738 if (check_port) {
11739 if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11740 port_result = -1;
11741 } else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11742 port_result = 1;
11743 }
11744
11745 if (result == 0) {
11746 result = port_result;
11747 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11748 return 2;
11749 }
11750 }
11751
11752 break;
11753 }
11754 default: {
11755 result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11756 break;
11757 }
11758 }
11759
11760 if (result < 0) {
11761 result = (-1);
11762 } else if (result > 0) {
11763 result = (1);
11764 }
11765
11766 return result;
11767 }
11768
11769 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11770 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11771 {
11772 u_int8_t mask;
11773
11774 /* Handle null pointers */
11775 if (p1 == NULL || p2 == NULL) {
11776 return p1 == p2;
11777 }
11778
11779 while (bits >= 8) {
11780 if (*p1++ != *p2++) {
11781 return FALSE;
11782 }
11783 bits -= 8;
11784 }
11785
11786 if (bits > 0) {
11787 mask = ~((1 << (8 - bits)) - 1);
11788 if ((*p1 & mask) != (*p2 & mask)) {
11789 return FALSE;
11790 }
11791 }
11792 return TRUE;
11793 }
11794
11795 static bool
necp_addr_is_empty(struct sockaddr * addr)11796 necp_addr_is_empty(struct sockaddr *addr)
11797 {
11798 if (addr == NULL) {
11799 return TRUE;
11800 }
11801
11802 if (addr->sa_len == 0) {
11803 return TRUE;
11804 }
11805
11806 switch (addr->sa_family) {
11807 case AF_INET: {
11808 static struct sockaddr_in ipv4_empty_address = {
11809 .sin_len = sizeof(struct sockaddr_in),
11810 .sin_family = AF_INET,
11811 .sin_port = 0,
11812 .sin_addr = { .s_addr = 0 }, // 0.0.0.0
11813 .sin_zero = {0},
11814 };
11815 if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11816 return TRUE;
11817 } else {
11818 return FALSE;
11819 }
11820 }
11821 case AF_INET6: {
11822 static struct sockaddr_in6 ipv6_empty_address = {
11823 .sin6_len = sizeof(struct sockaddr_in6),
11824 .sin6_family = AF_INET6,
11825 .sin6_port = 0,
11826 .sin6_flowinfo = 0,
11827 .sin6_addr = IN6ADDR_ANY_INIT, // ::
11828 .sin6_scope_id = 0,
11829 };
11830 if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11831 return TRUE;
11832 } else {
11833 return FALSE;
11834 }
11835 }
11836 default:
11837 return FALSE;
11838 }
11839
11840 return FALSE;
11841 }
11842
11843 static bool
necp_update_qos_marking(struct ifnet * ifp,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id)11844 necp_update_qos_marking(struct ifnet *ifp, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
11845 {
11846 bool qos_marking = FALSE;
11847 int exception_index = 0;
11848 struct necp_route_rule *route_rule = NULL;
11849
11850 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11851 if (route_rule == NULL) {
11852 qos_marking = FALSE;
11853 goto done;
11854 }
11855
11856 if (route_rule->match_netagent_id != 0) {
11857 if (netagent_array == NULL || netagent_array_count == 0) {
11858 // No agents, ignore rule
11859 goto done;
11860 }
11861 bool found_match = FALSE;
11862 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11863 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11864 found_match = TRUE;
11865 break;
11866 }
11867 }
11868 if (!found_match) {
11869 // Agents don't match, ignore rule
11870 goto done;
11871 }
11872 }
11873
11874 qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11875
11876 if (ifp == NULL) {
11877 goto done;
11878 }
11879
11880 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11881 if (route_rule->exception_if_indices[exception_index] == 0) {
11882 break;
11883 }
11884 if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
11885 continue;
11886 }
11887 if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
11888 qos_marking = TRUE;
11889 if (necp_debug > 2) {
11890 NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
11891 route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
11892 }
11893 goto done;
11894 }
11895 }
11896
11897 if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
11898 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
11899 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
11900 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
11901 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
11902 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
11903 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
11904 qos_marking = TRUE;
11905 if (necp_debug > 2) {
11906 NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d for Rule %d Allowed %d",
11907 route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
11908 route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action, route_rule_id, qos_marking);
11909 }
11910 goto done;
11911 }
11912 done:
11913 if (necp_debug > 1) {
11914 NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
11915 route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
11916 }
11917 return qos_marking;
11918 }
11919
11920 bool
necp_lookup_current_qos_marking(int32_t * qos_marking_gencount,struct rtentry * route,struct ifnet * interface,u_int32_t route_rule_id,bool old_qos_marking)11921 necp_lookup_current_qos_marking(int32_t *qos_marking_gencount, struct rtentry *route, struct ifnet *interface, u_int32_t route_rule_id, bool old_qos_marking)
11922 {
11923 bool new_qos_marking = old_qos_marking;
11924 struct ifnet *ifp = interface;
11925
11926 if (net_qos_policy_restricted == 0) {
11927 return new_qos_marking;
11928 }
11929
11930 /*
11931 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
11932 */
11933 if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
11934 return new_qos_marking;
11935 }
11936
11937 lck_rw_lock_shared(&necp_kernel_policy_lock);
11938
11939 if (ifp == NULL && route != NULL) {
11940 ifp = route->rt_ifp;
11941 }
11942 /*
11943 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
11944 */
11945 if (ifp == NULL || route_rule_id == 0) {
11946 new_qos_marking = FALSE;
11947 goto done;
11948 }
11949
11950 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11951 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11952 if (aggregate_route_rule != NULL) {
11953 int index = 0;
11954 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11955 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11956 if (sub_route_rule_id == 0) {
11957 break;
11958 }
11959 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
11960 if (new_qos_marking == TRUE) {
11961 break;
11962 }
11963 }
11964 }
11965 } else {
11966 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
11967 }
11968 /*
11969 * Now that we have an interface we remember the gencount
11970 */
11971 *qos_marking_gencount = necp_kernel_socket_policies_gencount;
11972
11973 done:
11974 lck_rw_done(&necp_kernel_policy_lock);
11975 return new_qos_marking;
11976 }
11977
11978 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)11979 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11980 {
11981 bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11982
11983 if (net_qos_policy_restricted == 0) {
11984 return;
11985 }
11986 if (inp->inp_socket == NULL) {
11987 return;
11988 }
11989 if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11990 return;
11991 }
11992
11993 qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
11994
11995 if (qos_marking == TRUE) {
11996 inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
11997 } else {
11998 inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
11999 }
12000 }
12001
12002 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)12003 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
12004 {
12005 if (ifp != NULL &&
12006 (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12007 ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12008 return true;
12009 }
12010 if (delegated_ifp != NULL &&
12011 (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12012 delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12013 return true;
12014 }
12015 return false;
12016 }
12017
12018 static bool
necp_route_is_allowed_inner(struct rtentry * route,struct ifnet * ifp,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * interface_type_denied)12019 necp_route_is_allowed_inner(struct rtentry *route, struct ifnet *ifp, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count,
12020 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12021 {
12022 bool default_is_allowed = TRUE;
12023 u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
12024 int exception_index = 0;
12025 struct ifnet *delegated_ifp = NULL;
12026 struct necp_route_rule *route_rule = NULL;
12027
12028 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12029 if (route_rule == NULL) {
12030 return TRUE;
12031 }
12032
12033 if (route_rule->match_netagent_id != 0) {
12034 if (netagent_array == NULL || netagent_array_count == 0) {
12035 // No agents, ignore rule
12036 return TRUE;
12037 }
12038 bool found_match = FALSE;
12039 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12040 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12041 found_match = TRUE;
12042 break;
12043 }
12044 }
12045 if (!found_match) {
12046 // Agents don't match, ignore rule
12047 return TRUE;
12048 }
12049 }
12050
12051 default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
12052 if (ifp == NULL && route != NULL) {
12053 ifp = route->rt_ifp;
12054 }
12055 if (ifp == NULL) {
12056 if (necp_debug > 1 && !default_is_allowed) {
12057 NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12058 }
12059 return default_is_allowed;
12060 }
12061
12062 delegated_ifp = ifp->if_delegated.ifp;
12063 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12064 if (route_rule->exception_if_indices[exception_index] == 0) {
12065 break;
12066 }
12067 if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
12068 (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
12069 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12070 const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
12071 if (necp_debug > 1 && lqm_abort) {
12072 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
12073 route_rule->exception_if_indices[exception_index], route_rule_id);
12074 }
12075 return false;
12076 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
12077 if (necp_debug > 1) {
12078 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));
12079 }
12080 if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
12081 *interface_type_denied = route_rule->effective_type;
12082 }
12083 return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
12084 }
12085 }
12086 }
12087
12088 if (IFNET_IS_CELLULAR(ifp)) {
12089 if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12090 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12091 if (interface_type_denied != NULL) {
12092 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12093 if (route_rule->effective_type != 0) {
12094 *interface_type_denied = route_rule->effective_type;
12095 }
12096 }
12097 // Mark aggregate action as deny
12098 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12099 }
12100 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
12101 if (interface_type_denied != NULL) {
12102 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12103 if (route_rule->effective_type != 0) {
12104 *interface_type_denied = route_rule->effective_type;
12105 }
12106 }
12107 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12108 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12109 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
12110 // Deny wins if there is a conflict
12111 type_aggregate_action = route_rule->cellular_action;
12112 }
12113 }
12114 }
12115
12116 if (IFNET_IS_WIFI(ifp)) {
12117 if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12118 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12119 if (interface_type_denied != NULL) {
12120 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12121 if (route_rule->effective_type != 0) {
12122 *interface_type_denied = route_rule->effective_type;
12123 }
12124 }
12125 // Mark aggregate action as deny
12126 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12127 }
12128 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
12129 if (interface_type_denied != NULL) {
12130 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12131 if (route_rule->effective_type != 0) {
12132 *interface_type_denied = route_rule->effective_type;
12133 }
12134 }
12135 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12136 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12137 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
12138 // Deny wins if there is a conflict
12139 type_aggregate_action = route_rule->wifi_action;
12140 }
12141 }
12142 }
12143
12144 if (IFNET_IS_COMPANION_LINK(ifp) ||
12145 (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
12146 if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12147 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12148 if (interface_type_denied != NULL) {
12149 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12150 if (route_rule->effective_type != 0) {
12151 *interface_type_denied = route_rule->effective_type;
12152 }
12153 }
12154 // Mark aggregate action as deny
12155 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12156 }
12157 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
12158 if (interface_type_denied != NULL) {
12159 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12160 if (route_rule->effective_type != 0) {
12161 *interface_type_denied = route_rule->effective_type;
12162 }
12163 }
12164 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12165 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12166 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
12167 // Deny wins if there is a conflict
12168 type_aggregate_action = route_rule->companion_action;
12169 }
12170 }
12171 }
12172
12173 if (IFNET_IS_WIRED(ifp)) {
12174 if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12175 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12176 if (interface_type_denied != NULL) {
12177 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12178 if (route_rule->effective_type != 0) {
12179 *interface_type_denied = route_rule->effective_type;
12180 }
12181 }
12182 // Mark aggregate action as deny
12183 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12184 }
12185 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
12186 if (interface_type_denied != NULL) {
12187 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12188 if (route_rule->effective_type != 0) {
12189 *interface_type_denied = route_rule->effective_type;
12190 }
12191 }
12192 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12193 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12194 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
12195 // Deny wins if there is a conflict
12196 type_aggregate_action = route_rule->wired_action;
12197 }
12198 }
12199 }
12200
12201 if (IFNET_IS_EXPENSIVE(ifp)) {
12202 if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12203 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12204 // Mark aggregate action as deny
12205 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12206 }
12207 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
12208 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12209 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12210 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
12211 // Deny wins if there is a conflict
12212 type_aggregate_action = route_rule->expensive_action;
12213 }
12214 }
12215 }
12216
12217 if (IFNET_IS_CONSTRAINED(ifp)) {
12218 if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12219 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12220 // Mark aggregate action as deny
12221 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12222 }
12223 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
12224 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12225 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12226 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
12227 // Deny wins if there is a conflict
12228 type_aggregate_action = route_rule->constrained_action;
12229 }
12230 }
12231 }
12232
12233 if (IFNET_IS_VPN(ifp)) {
12234 if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12235 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12236 // Mark aggregate action as deny
12237 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12238 }
12239 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
12240 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12241 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12242 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
12243 // Deny wins if there is a conflict
12244 type_aggregate_action = route_rule->vpn_action;
12245 }
12246 }
12247 }
12248
12249 if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
12250 if (necp_debug > 1) {
12251 NECPLOG(LOG_DEBUG, "Route Allowed: C:%d WF:%d W:%d E:%d Cmpn:%d VPN:%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->vpn_action, route_rule_id, (IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE));
12252 }
12253 return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
12254 }
12255
12256 if (necp_debug > 1 && !default_is_allowed) {
12257 NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12258 }
12259 return default_is_allowed;
12260 }
12261
12262 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)12263 necp_proc_is_allowed_on_management_interface(proc_t proc)
12264 {
12265 bool allowed = false;
12266 const task_t __single task = proc_task(proc);
12267
12268 if (task != NULL) {
12269 if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
12270 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
12271 #if DEBUG || DEVELOPMENT
12272 || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
12273 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
12274 #endif /* DEBUG || DEVELOPMENT */
12275 ) {
12276 allowed = true;
12277 }
12278 }
12279 return allowed;
12280 }
12281
12282 __attribute__((noinline))
12283 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)12284 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12285 {
12286 char buf[128];
12287
12288 if (inp != NULL) {
12289 inp_snprintf_tuple(inp, buf, sizeof(buf));
12290 } else {
12291 *buf = 0;
12292 }
12293 os_log(OS_LOG_DEFAULT,
12294 "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
12295 proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
12296 proc != NULL ? proc_getpid(proc) : proc_selfpid(),
12297 inp != NULL ? buf : "",
12298 ifp->if_xname);
12299 }
12300
12301 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)12302 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12303 {
12304 if (if_management_interface_check_needed == false) {
12305 return true;
12306 }
12307 if (necp_drop_management_order == 0) {
12308 return true;
12309 }
12310 if (ifp == NULL && route != NULL) {
12311 ifp = route->rt_ifp;
12312 }
12313 if (ifp == NULL) {
12314 return true;
12315 }
12316
12317 if (IFNET_IS_MANAGEMENT(ifp)) {
12318 bool allowed = true;
12319
12320 if (inp != NULL) {
12321 /*
12322 * The entitlement check is already performed for socket flows
12323 */
12324 allowed = INP_MANAGEMENT_ALLOWED(inp);
12325 } else if (proc != NULL) {
12326 allowed = necp_proc_is_allowed_on_management_interface(proc);
12327 }
12328 if (__improbable(if_management_verbose > 1 && allowed == false)) {
12329 necp_log_interface_not_allowed(ifp, proc, inp);
12330 }
12331 return allowed;
12332 }
12333 return true;
12334 }
12335
12336 static bool
necp_route_is_allowed(struct rtentry * route,struct ifnet * interface,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * interface_type_denied)12337 necp_route_is_allowed(struct rtentry *route, struct ifnet *interface, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count,
12338 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12339 {
12340 if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
12341 if (necp_debug > 1) {
12342 NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
12343 }
12344 return TRUE;
12345 }
12346
12347 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12348 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12349 if (aggregate_route_rule != NULL) {
12350 int index = 0;
12351 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12352 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12353 if (sub_route_rule_id == 0) {
12354 break;
12355 }
12356 if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
12357 return FALSE;
12358 }
12359 }
12360 }
12361 } else {
12362 return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
12363 }
12364
12365 return TRUE;
12366 }
12367
12368 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)12369 necp_route_rule_matches_agents(u_int32_t route_rule_id)
12370 {
12371 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12372 if (route_rule == NULL) {
12373 return false;
12374 }
12375
12376 return route_rule->match_netagent_id != 0;
12377 }
12378
12379 static uint32_t
necp_route_get_netagent(struct rtentry * route,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,bool * remove)12380 necp_route_get_netagent(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove)
12381 {
12382 if (remove == NULL) {
12383 return 0;
12384 }
12385
12386 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12387 if (route_rule == NULL) {
12388 return 0;
12389 }
12390
12391 // No netagent, skip
12392 if (route_rule->netagent_id == 0) {
12393 return 0;
12394 }
12395
12396 if (route_rule->match_netagent_id != 0) {
12397 if (netagent_array == NULL || netagent_array_count == 0) {
12398 // No agents, ignore rule
12399 return 0;
12400 }
12401 bool found_match = FALSE;
12402 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12403 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12404 found_match = TRUE;
12405 break;
12406 }
12407 }
12408 if (!found_match) {
12409 // Agents don't match, ignore rule
12410 return 0;
12411 }
12412 }
12413
12414 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12415 if (ifp == NULL) {
12416 // No interface, apply the default action
12417 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12418 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12419 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12420 return route_rule->netagent_id;
12421 }
12422 return 0;
12423 }
12424
12425 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12426 if (route_rule->exception_if_indices[exception_index] == 0) {
12427 break;
12428 }
12429 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12430 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12431 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12432 route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12433 *remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12434 return route_rule->netagent_id;
12435 }
12436 return 0;
12437 }
12438 }
12439
12440 if (ifp->if_type == IFT_CELLULAR &&
12441 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12442 if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12443 route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12444 *remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12445 return route_rule->netagent_id;
12446 }
12447 return 0;
12448 }
12449
12450 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12451 route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12452 if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12453 route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12454 *remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12455 return route_rule->netagent_id;
12456 }
12457 return 0;
12458 }
12459
12460 if (IFNET_IS_COMPANION_LINK(ifp) &&
12461 route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12462 if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12463 route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12464 *remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12465 return route_rule->netagent_id;
12466 }
12467 return 0;
12468 }
12469
12470 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12471 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12472 if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12473 route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12474 *remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12475 return route_rule->netagent_id;
12476 }
12477 return 0;
12478 }
12479
12480 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12481 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12482 if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12483 route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12484 *remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12485 return route_rule->netagent_id;
12486 }
12487 return 0;
12488 }
12489
12490 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12491 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12492 if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12493 route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12494 *remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12495 return route_rule->netagent_id;
12496 }
12497 return 0;
12498 }
12499
12500 if (ifp->if_xflags & IFXF_IS_VPN &&
12501 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12502 if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12503 route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12504 *remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12505 return route_rule->netagent_id;
12506 }
12507 return 0;
12508 }
12509
12510 // No more specific case matched, apply the default action
12511 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12512 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12513 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12514 return route_rule->netagent_id;
12515 }
12516
12517 return 0;
12518 }
12519
12520 static uint32_t
necp_route_get_flow_divert_inner(struct rtentry * route,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id)12521 necp_route_get_flow_divert_inner(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
12522 {
12523 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12524 if (route_rule == NULL) {
12525 return 0;
12526 }
12527
12528 // No control unit, skip
12529 if (route_rule->control_unit == 0) {
12530 return 0;
12531 }
12532
12533 if (route_rule->match_netagent_id != 0) {
12534 if (netagent_array == NULL || netagent_array_count == 0) {
12535 // No agents, ignore rule
12536 return 0;
12537 }
12538 bool found_match = FALSE;
12539 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12540 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12541 found_match = TRUE;
12542 break;
12543 }
12544 }
12545 if (!found_match) {
12546 // Agents don't match, ignore rule
12547 return 0;
12548 }
12549 }
12550
12551 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12552 if (ifp == NULL) {
12553 // No interface, apply the default action
12554 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12555 return route_rule->control_unit;
12556 }
12557 return 0;
12558 }
12559
12560 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12561 if (route_rule->exception_if_indices[exception_index] == 0) {
12562 break;
12563 }
12564 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12565 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12566 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12567 return route_rule->control_unit;
12568 }
12569 return 0;
12570 }
12571 }
12572
12573 if (ifp->if_type == IFT_CELLULAR &&
12574 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12575 if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12576 return route_rule->control_unit;
12577 }
12578 return 0;
12579 }
12580
12581 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12582 route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12583 if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12584 return route_rule->control_unit;
12585 }
12586 return 0;
12587 }
12588
12589 if (IFNET_IS_COMPANION_LINK(ifp) &&
12590 route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12591 if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12592 return route_rule->control_unit;
12593 }
12594 return 0;
12595 }
12596
12597 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12598 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12599 if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12600 return route_rule->control_unit;
12601 }
12602 return 0;
12603 }
12604
12605 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12606 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12607 if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12608 return route_rule->control_unit;
12609 }
12610 return 0;
12611 }
12612
12613 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12614 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12615 if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12616 return route_rule->control_unit;
12617 }
12618 return 0;
12619 }
12620
12621 if (ifp->if_xflags & IFXF_IS_VPN &&
12622 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12623 if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12624 return route_rule->control_unit;
12625 }
12626 return 0;
12627 }
12628
12629 // No more specific case matched, apply the default action
12630 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12631 return route_rule->control_unit;
12632 }
12633 return 0;
12634 }
12635
12636 static uint32_t
necp_route_get_flow_divert(struct rtentry * route,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * flow_divert_aggregate_unit)12637 necp_route_get_flow_divert(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id,
12638 u_int32_t *flow_divert_aggregate_unit)
12639 {
12640 if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12641 return 0;
12642 }
12643
12644 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12645 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12646 if (aggregate_route_rule != NULL) {
12647 int index = 0;
12648 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12649 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12650 if (sub_route_rule_id == 0) {
12651 break;
12652 }
12653 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12654 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12655 // For transparent proxies, accumulate the control unit and continue to the next route rule
12656 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12657 continue;
12658 }
12659
12660 if (control_unit != 0) {
12661 return control_unit;
12662 }
12663 }
12664 }
12665 } else {
12666 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12667 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12668 // For transparent proxies, accumulate the control unit and let the caller continue
12669 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12670 return 0;
12671 }
12672 return control_unit;
12673 }
12674
12675 return 0;
12676 }
12677
12678 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12679 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12680 {
12681 bool is_allowed = true;
12682 u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12683 if (route_rule_id != 0 &&
12684 interface != NULL) {
12685 lck_rw_lock_shared(&necp_kernel_policy_lock);
12686 is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
12687 lck_rw_done(&necp_kernel_policy_lock);
12688 }
12689 return is_allowed;
12690 }
12691
12692 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12693 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12694 {
12695 size_t netagent_cursor;
12696 for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12697 struct necp_uuid_id_mapping *mapping = NULL;
12698 u_int32_t netagent_id = netagent_ids[netagent_cursor];
12699 if (netagent_id == 0) {
12700 continue;
12701 }
12702 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
12703 if (mapping != NULL) {
12704 u_int32_t agent_flags = 0;
12705 agent_flags = netagent_get_flags(mapping->uuid);
12706 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12707 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12708 continue;
12709 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12710 return FALSE;
12711 }
12712 }
12713 }
12714 }
12715 return TRUE;
12716 }
12717
12718 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12719 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12720 {
12721 bool allowed_to_receive = TRUE;
12722
12723 if (pf_tag == PF_TAG_ID_STACK_DROP &&
12724 (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12725 allowed_to_receive = FALSE;
12726 }
12727
12728 return allowed_to_receive;
12729 }
12730
12731 static bool
necp_socket_is_allowed_to_send_recv_internal(struct inpcb * inp,struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,ifnet_t input_interface,u_int16_t pf_tag,necp_kernel_policy_id * return_policy_id,u_int32_t * return_route_rule_id,necp_kernel_policy_id * return_skip_policy_id,u_int32_t * return_pass_flags)12732 necp_socket_is_allowed_to_send_recv_internal(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, ifnet_t input_interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id, u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
12733 {
12734 u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12735 bool allowed_to_receive = TRUE;
12736 struct necp_socket_info info = {};
12737 u_int32_t flowhash = 0;
12738 necp_kernel_policy_result service_action = 0;
12739 necp_kernel_policy_service service = { 0, 0 };
12740 u_int32_t route_rule_id = 0;
12741 struct rtentry *route = NULL;
12742 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12743 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12744 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12745 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12746 proc_t __single socket_proc = NULL;
12747 necp_kernel_policy_filter filter_control_unit = 0;
12748 u_int32_t pass_flags = 0;
12749 u_int32_t flow_divert_aggregate_unit = 0;
12750 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12751 int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12752
12753 memset(&netagent_ids, 0, sizeof(netagent_ids));
12754
12755 if (return_policy_id) {
12756 *return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12757 }
12758 if (return_skip_policy_id) {
12759 *return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12760 }
12761 if (return_route_rule_id) {
12762 *return_route_rule_id = 0;
12763 }
12764 if (return_pass_flags) {
12765 *return_pass_flags = 0;
12766 }
12767
12768 if (inp == NULL) {
12769 goto done;
12770 }
12771
12772 route = inp->inp_route.ro_rt;
12773
12774 struct socket *so = inp->inp_socket;
12775
12776 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12777
12778 // Don't lock. Possible race condition, but we don't want the performance hit.
12779 if (necp_drop_management_order == 0 &&
12780 (necp_kernel_socket_policies_count == 0 ||
12781 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12782 if (necp_drop_all_order > 0 || drop_order > 0) {
12783 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12784 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12785 allowed_to_receive = TRUE;
12786 } else {
12787 allowed_to_receive = FALSE;
12788 }
12789 }
12790 goto done;
12791 }
12792
12793 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
12794 if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12795 bool policies_have_changed = FALSE;
12796 bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12797 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12798 policies_have_changed = TRUE;
12799 } else {
12800 if (inp->inp_policyresult.results.route_rule_id != 0) {
12801 lck_rw_lock_shared(&necp_kernel_policy_lock);
12802 if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
12803 route_allowed = FALSE;
12804 }
12805 lck_rw_done(&necp_kernel_policy_lock);
12806 }
12807 }
12808
12809 if (!policies_have_changed) {
12810 if (debug) {
12811 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, input_interface != NULL ? SOFLOW_DIRECTION_INBOUND : SOFLOW_DIRECTION_OUTBOUND, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), verifyifindex);
12812 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12813 }
12814
12815 if (!route_allowed ||
12816 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12817 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12818 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12819 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12820 allowed_to_receive = FALSE;
12821 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START - RESULT - CACHED DROP", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12822 } else {
12823 if (return_policy_id) {
12824 *return_policy_id = inp->inp_policyresult.policy_id;
12825 }
12826 if (return_skip_policy_id) {
12827 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12828 }
12829 if (return_route_rule_id) {
12830 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12831 }
12832 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12833 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12834 }
12835 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START - RESULT - CACHED", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12836 }
12837 goto done;
12838 }
12839 }
12840
12841 // Check for loopback exception
12842 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12843 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12844 allowed_to_receive = FALSE;
12845 goto done;
12846 }
12847 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
12848 allowed_to_receive = TRUE;
12849 goto done;
12850 }
12851
12852 // Actually calculate policy result
12853 lck_rw_lock_shared(&necp_kernel_policy_lock);
12854 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, input_interface != NULL ? SOFLOW_DIRECTION_INBOUND : SOFLOW_DIRECTION_OUTBOUND, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), verifyifindex);
12855
12856 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12857 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
12858
12859 flowhash = necp_socket_calc_flowhash_locked(&info);
12860 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12861 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
12862 inp->inp_policyresult.flowhash == flowhash) {
12863 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12864 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12865 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12866 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
12867 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12868 (inp->inp_policyresult.results.route_rule_id != 0 &&
12869 !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
12870 allowed_to_receive = FALSE;
12871 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <DROP>", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12872 } else {
12873 if (return_policy_id) {
12874 *return_policy_id = inp->inp_policyresult.policy_id;
12875 }
12876 if (return_route_rule_id) {
12877 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12878 }
12879 if (return_skip_policy_id) {
12880 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12881 }
12882 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12883 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12884 }
12885 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12886 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",
12887 inp->inp_socket, info.bound_interface_index, info.protocol,
12888 inp->inp_policyresult.policy_id,
12889 inp->inp_policyresult.skip_policy_id,
12890 inp->inp_policyresult.results.result,
12891 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
12892 }
12893 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
12894 return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12895 }
12896 lck_rw_done(&necp_kernel_policy_lock);
12897 goto done;
12898 }
12899
12900 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
12901 size_t route_rule_id_array_count = 0;
12902 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
12903 struct necp_kernel_socket_policy *matched_policy =
12904 necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
12905 &info,
12906 &filter_control_unit,
12907 route_rule_id_array,
12908 &route_rule_id_array_count,
12909 MAX_AGGREGATE_ROUTE_RULES,
12910 &service_action,
12911 &service,
12912 netagent_ids,
12913 NECP_MAX_NETAGENTS,
12914 NULL,
12915 0,
12916 NULL,
12917 0,
12918 effective_proc,
12919 pf_tag,
12920 return_skip_policy_id,
12921 inp->inp_route.ro_rt,
12922 &drop_dest_policy_result,
12923 &drop_all_bypass,
12924 &flow_divert_aggregate_unit,
12925 so,
12926 debug);
12927
12928 // Check for loopback exception again after the policy match
12929 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
12930 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
12931 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
12932 // If policies haven't changed since last evaluation, do not update filter result in order to
12933 // preserve the very first filter result for the socket. Otherwise, update the filter result to
12934 // allow content filter to detect and drop pre-existing flows.
12935 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
12936 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
12937 if (info.soflow_entry != NULL) {
12938 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
12939 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
12940 }
12941 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
12942 current_filter_control_unit != filter_control_unit) {
12943 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12944 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12945 if (info.soflow_entry != NULL) {
12946 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
12947 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
12948 }
12949 }
12950 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12951 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12952 }
12953 allowed_to_receive = TRUE;
12954 lck_rw_done(&necp_kernel_policy_lock);
12955
12956 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - loopback", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12957 goto done;
12958 }
12959
12960 if (info.protocol != IPPROTO_UDP) {
12961 goto skip_agent_check;
12962 }
12963
12964 // Verify netagents
12965 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
12966 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12967 NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Dropping packet because agent is not active", (uint64_t)VM_KERNEL_ADDRPERM(so), info.bound_interface_index, info.protocol);
12968 }
12969
12970 // Mark socket as a drop if required agent is not active
12971 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12972 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12973 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12974 inp->inp_policyresult.flowhash = flowhash;
12975 inp->inp_policyresult.results.filter_control_unit = 0;
12976 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
12977 inp->inp_policyresult.results.route_rule_id = 0;
12978 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
12979 if (info.soflow_entry != NULL) {
12980 info.soflow_entry->soflow_filter_control_unit = 0;
12981 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
12982 }
12983
12984 // Unlock
12985 allowed_to_receive = FALSE;
12986 lck_rw_done(&necp_kernel_policy_lock);
12987
12988 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - AGENT INACTIVE", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12989
12990 goto done;
12991 }
12992
12993 skip_agent_check:
12994
12995 if (route_rule_id_array_count == 1) {
12996 route_rule_id = route_rule_id_array[0];
12997 } else if (route_rule_id_array_count > 1) {
12998 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
12999 }
13000
13001 bool send_local_network_denied_event = false;
13002 if (matched_policy != NULL) {
13003 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
13004 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
13005 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
13006 // Trigger the event that we dropped due to a local network policy
13007 send_local_network_denied_event = true;
13008 }
13009
13010 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
13011 matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13012 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13013 matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
13014 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13015 (route_rule_id != 0 &&
13016 !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
13017 !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
13018 allowed_to_receive = FALSE;
13019 } else {
13020 if (return_policy_id) {
13021 *return_policy_id = matched_policy->id;
13022 }
13023 if (return_route_rule_id) {
13024 *return_route_rule_id = route_rule_id;
13025 }
13026 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
13027 pass_flags = matched_policy->result_parameter.pass_flags;
13028 }
13029 // If policies haven't changed since last evaluation, do not update filter result in order to
13030 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13031 // allow content filter to detect and drop pre-existing flows.
13032 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13033 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13034 if (info.soflow_entry != NULL) {
13035 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13036 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13037 }
13038 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13039 current_filter_control_unit != filter_control_unit) {
13040 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13041 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13042 if (info.soflow_entry != NULL) {
13043 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13044 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13045 }
13046 }
13047 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13048 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13049 }
13050 }
13051
13052 if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
13053 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>",
13054 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);
13055 }
13056 } else {
13057 bool drop_all = false;
13058 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
13059 drop_all = true;
13060 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
13061 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
13062 }
13063 }
13064 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
13065 allowed_to_receive = FALSE;
13066 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
13067 } else {
13068 if (return_policy_id) {
13069 *return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13070 }
13071 if (return_route_rule_id) {
13072 *return_route_rule_id = route_rule_id;
13073 }
13074
13075 // If policies haven't changed since last evaluation, do not update filter result in order to
13076 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13077 // allow content filter to detect and drop pre-existing flows.
13078 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13079 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13080 if (info.soflow_entry != NULL) {
13081 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13082 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13083 }
13084 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13085 current_filter_control_unit != filter_control_unit) {
13086 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13087 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13088 if (info.soflow_entry != NULL) {
13089 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13090 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13091 }
13092 }
13093 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13094 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13095 }
13096 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - NO MATCH", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
13097 }
13098 }
13099
13100 if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
13101 allowed_to_receive = FALSE;
13102 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
13103 }
13104
13105 lck_rw_done(&necp_kernel_policy_lock);
13106
13107 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
13108 inp->inp_policyresult.network_denied_notifies++;
13109 #if defined(XNU_TARGET_OS_OSX)
13110 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
13111 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13112 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13113 NETPOLICY_NETWORKTYPE_LOCAL);
13114 #else
13115 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13116 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13117 NETPOLICY_NETWORKTYPE_LOCAL);
13118 #endif
13119 }
13120
13121 done:
13122 if (return_pass_flags != NULL) {
13123 *return_pass_flags = pass_flags;
13124 }
13125
13126 if (pf_tag != 0 && allowed_to_receive) {
13127 allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
13128 }
13129
13130 if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
13131 soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
13132 }
13133
13134 if (socket_proc) {
13135 proc_rele(socket_proc);
13136 }
13137
13138 if (info.soflow_entry != NULL) {
13139 soflow_free_flow(info.soflow_entry);
13140 }
13141
13142 return allowed_to_receive;
13143 }
13144
13145 bool
necp_socket_is_allowed_to_send_recv_v4(struct inpcb * inp,u_int16_t local_port,u_int16_t remote_port,struct in_addr * local_addr,struct in_addr * remote_addr,ifnet_t input_interface,u_int16_t pf_tag,necp_kernel_policy_id * return_policy_id,u_int32_t * return_route_rule_id,necp_kernel_policy_id * return_skip_policy_id,u_int32_t * return_pass_flags)13146 necp_socket_is_allowed_to_send_recv_v4(struct inpcb *inp, u_int16_t local_port, u_int16_t remote_port, struct in_addr *local_addr, struct in_addr *remote_addr, ifnet_t input_interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id, u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13147 {
13148 struct sockaddr_in local = {};
13149 struct sockaddr_in remote = {};
13150 local.sin_family = remote.sin_family = AF_INET;
13151 local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
13152 local.sin_port = local_port;
13153 remote.sin_port = remote_port;
13154 memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
13155 memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
13156
13157 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13158 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13159 }
13160
13161 bool
necp_socket_is_allowed_to_send_recv_v6(struct inpcb * inp,u_int16_t local_port,u_int16_t remote_port,struct in6_addr * local_addr,struct in6_addr * remote_addr,ifnet_t input_interface,u_int16_t pf_tag,necp_kernel_policy_id * return_policy_id,u_int32_t * return_route_rule_id,necp_kernel_policy_id * return_skip_policy_id,u_int32_t * return_pass_flags)13162 necp_socket_is_allowed_to_send_recv_v6(struct inpcb *inp, u_int16_t local_port, u_int16_t remote_port, struct in6_addr *local_addr, struct in6_addr *remote_addr, ifnet_t input_interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id, u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13163 {
13164 struct sockaddr_in6 local = {};
13165 struct sockaddr_in6 remote = {};
13166 local.sin6_family = remote.sin6_family = AF_INET6;
13167 local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
13168 local.sin6_port = local_port;
13169 remote.sin6_port = remote_port;
13170 memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
13171 memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
13172
13173 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13174 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13175 }
13176
13177 bool
necp_socket_is_allowed_to_send_recv(struct inpcb * inp,ifnet_t input_interface,u_int16_t pf_tag,necp_kernel_policy_id * return_policy_id,u_int32_t * return_route_rule_id,necp_kernel_policy_id * return_skip_policy_id,u_int32_t * return_pass_flags)13178 necp_socket_is_allowed_to_send_recv(struct inpcb *inp, ifnet_t input_interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id,
13179 u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13180 {
13181 return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
13182 return_policy_id, return_route_rule_id,
13183 return_skip_policy_id, return_pass_flags);
13184 }
13185
13186 int
necp_mark_packet_from_socket(struct mbuf * packet,struct inpcb * inp,necp_kernel_policy_id policy_id,u_int32_t route_rule_id,necp_kernel_policy_id skip_policy_id,u_int32_t pass_flags)13187 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
13188 necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
13189 {
13190 if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
13191 return EINVAL;
13192 }
13193
13194 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13195 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
13196 policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
13197 }
13198
13199 // Mark ID for Pass and IP Tunnel
13200 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13201 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13202 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
13203 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
13204 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13205 } else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
13206 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
13207 // This case is same as a PASS
13208 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13209 } else {
13210 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13211 }
13212 packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
13213 if (route_rule_id != 0) {
13214 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
13215 } else {
13216 packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13217 }
13218 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);
13219
13220 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13221 skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13222 // Only mark the skip policy if it is a valid policy ID
13223 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13224 } else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13225 inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13226 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13227 } else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
13228 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
13229 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
13230 // See necp_get_skip_policy_id_from_packet() and
13231 // necp_packet_should_skip_filters().
13232 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13233 } else {
13234 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13235 }
13236
13237 if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
13238 ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
13239 m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
13240 }
13241
13242 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13243 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
13244 packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
13245 }
13246
13247 return 0;
13248 }
13249
13250 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)13251 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
13252 {
13253 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13254 return EINVAL;
13255 }
13256
13257 // Mark ID for Pass and IP Tunnel
13258 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13259 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13260 } else {
13261 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13262 }
13263
13264 return 0;
13265 }
13266
13267 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)13268 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
13269 {
13270 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13271 return EINVAL;
13272 }
13273
13274 // Mark ID for Pass and IP Tunnel
13275 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13276 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13277 } else {
13278 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13279 }
13280
13281 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13282 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13283 } else {
13284 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13285 }
13286 return 0;
13287 }
13288
13289 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)13290 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
13291 {
13292 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13293 return EINVAL;
13294 }
13295
13296 // Mark ID for Pass and IP Tunnel
13297 if (interface != NULL) {
13298 packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
13299 }
13300
13301 return 0;
13302 }
13303
13304 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)13305 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
13306 {
13307 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13308 return EINVAL;
13309 }
13310
13311 if (is_keepalive) {
13312 packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
13313 } else {
13314 packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
13315 }
13316
13317 return 0;
13318 }
13319
13320 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)13321 necp_get_policy_id_from_packet(struct mbuf *packet)
13322 {
13323 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13324 return NECP_KERNEL_POLICY_ID_NONE;
13325 }
13326
13327 return packet->m_pkthdr.necp_mtag.necp_policy_id;
13328 }
13329
13330 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)13331 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
13332 {
13333 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13334 return NECP_KERNEL_POLICY_ID_NONE;
13335 }
13336
13337 // Check for overloaded value. See necp_mark_packet_from_socket().
13338 if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
13339 return NECP_KERNEL_POLICY_ID_NONE;
13340 }
13341
13342 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
13343 }
13344
13345 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)13346 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
13347 {
13348 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13349 return 0;
13350 }
13351
13352 return m_pftag(packet)->pftag_tag;
13353 }
13354
13355 bool
necp_packet_should_skip_filters(struct mbuf * packet)13356 necp_packet_should_skip_filters(struct mbuf *packet)
13357 {
13358 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13359 return false;
13360 }
13361
13362 // Check for overloaded value. See necp_mark_packet_from_socket().
13363 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
13364 }
13365
13366 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)13367 necp_get_last_interface_index_from_packet(struct mbuf *packet)
13368 {
13369 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13370 return 0;
13371 }
13372
13373 return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
13374 }
13375
13376 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)13377 necp_get_route_rule_id_from_packet(struct mbuf *packet)
13378 {
13379 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13380 return 0;
13381 }
13382
13383 return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
13384 }
13385
13386 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)13387 necp_get_app_uuid_from_packet(struct mbuf *packet,
13388 uuid_t app_uuid)
13389 {
13390 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13391 return EINVAL;
13392 }
13393
13394 bool found_mapping = FALSE;
13395 if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
13396 lck_rw_lock_shared(&necp_kernel_policy_lock);
13397 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);
13398 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
13399 if (entry != NULL) {
13400 uuid_copy(app_uuid, entry->uuid);
13401 found_mapping = true;
13402 }
13403 lck_rw_done(&necp_kernel_policy_lock);
13404 }
13405 if (!found_mapping) {
13406 uuid_clear(app_uuid);
13407 }
13408 return 0;
13409 }
13410
13411 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)13412 necp_get_is_keepalive_from_packet(struct mbuf *packet)
13413 {
13414 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13415 return FALSE;
13416 }
13417
13418 return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
13419 }
13420
13421 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)13422 necp_socket_get_content_filter_control_unit(struct socket *so)
13423 {
13424 struct inpcb *inp = sotoinpcb(so);
13425
13426 if (inp == NULL) {
13427 return 0;
13428 }
13429 return inp->inp_policyresult.results.filter_control_unit;
13430 }
13431
13432 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)13433 necp_socket_get_policy_gencount(struct socket *so)
13434 {
13435 struct inpcb *inp = so ? sotoinpcb(so) : NULL;
13436
13437 if (inp == NULL) {
13438 return 0;
13439 }
13440 return inp->inp_policyresult.policy_gencount;
13441 }
13442
13443 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)13444 necp_socket_should_use_flow_divert(struct inpcb *inp)
13445 {
13446 if (inp == NULL) {
13447 return FALSE;
13448 }
13449
13450 return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
13451 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13452 (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
13453 }
13454
13455 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)13456 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
13457 {
13458 if (inp == NULL) {
13459 return 0;
13460 }
13461
13462 if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13463 return 0;
13464 }
13465
13466 if (aggregate_unit != NULL &&
13467 inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13468 *aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13469 }
13470
13471 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13472 return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13473 }
13474
13475 return 0;
13476 }
13477
13478 bool
necp_socket_should_rescope(struct inpcb * inp)13479 necp_socket_should_rescope(struct inpcb *inp)
13480 {
13481 if (inp == NULL) {
13482 return FALSE;
13483 }
13484
13485 return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13486 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13487 }
13488
13489 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13490 necp_socket_get_rescope_if_index(struct inpcb *inp)
13491 {
13492 if (inp == NULL) {
13493 return 0;
13494 }
13495
13496 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13497 return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13498 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13499 return necp_get_primary_direct_interface_index();
13500 }
13501
13502 return 0;
13503 }
13504
13505 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13506 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13507 {
13508 if (inp == NULL) {
13509 return current_mtu;
13510 }
13511
13512 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13513 (inp->inp_flags & INP_BOUND_IF) &&
13514 inp->inp_boundifp) {
13515 u_int bound_interface_index = inp->inp_boundifp->if_index;
13516 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13517
13518 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13519 if (bound_interface_index != tunnel_interface_index) {
13520 ifnet_t tunnel_interface = NULL;
13521
13522 ifnet_head_lock_shared();
13523 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13524 ifnet_head_done();
13525
13526 if (tunnel_interface != NULL) {
13527 u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13528 u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13529 const char ipsec_prefix[] = "ipsec";
13530 if (delegate_tunnel_mtu != 0 &&
13531 strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13532 // For ipsec interfaces, calculate the overhead from the delegate interface
13533 u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13534 if (delegate_tunnel_mtu > tunnel_overhead) {
13535 delegate_tunnel_mtu -= tunnel_overhead;
13536 }
13537
13538 if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13539 // If the (delegate - overhead) < direct, return (delegate - overhead)
13540 return delegate_tunnel_mtu;
13541 } else {
13542 // Otherwise return direct
13543 return direct_tunnel_mtu;
13544 }
13545 } else {
13546 // For non-ipsec interfaces, just return the tunnel MTU
13547 return direct_tunnel_mtu;
13548 }
13549 }
13550 }
13551 }
13552
13553 // By default, just return the MTU passed in
13554 return current_mtu;
13555 }
13556
13557 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13558 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13559 {
13560 if (result_parameter == NULL) {
13561 return NULL;
13562 }
13563
13564 return ifindex2ifnet[result_parameter->tunnel_interface_index];
13565 }
13566
13567 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13568 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13569 {
13570 bool found_match = FALSE;
13571 bool can_rebind = FALSE;
13572 ifaddr_t ifa;
13573 union necp_sockaddr_union address_storage;
13574
13575 if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13576 return FALSE;
13577 }
13578
13579 // Match source address against interface addresses
13580 ifnet_lock_shared(interface);
13581 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13582 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13583 if (address_storage.sa.sa_family != family) {
13584 continue;
13585 }
13586
13587 if (family == AF_INET) {
13588 struct ip *ip = mtod(packet, struct ip *);
13589 if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13590 found_match = TRUE;
13591 break;
13592 }
13593 } else if (family == AF_INET6) {
13594 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13595 if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13596 found_match = TRUE;
13597 break;
13598 }
13599 }
13600 }
13601 }
13602 const uint32_t if_idx = interface->if_index;
13603 ifnet_lock_done(interface);
13604
13605 // If source address matched, attempt to construct a route to the destination address
13606 if (found_match) {
13607 ROUTE_RELEASE(new_route);
13608
13609 if (family == AF_INET) {
13610 struct ip *ip = mtod(packet, struct ip *);
13611 struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13612 dst4->sin_family = AF_INET;
13613 dst4->sin_len = sizeof(struct sockaddr_in);
13614 dst4->sin_addr = ip->ip_dst;
13615 rtalloc_scoped(new_route, if_idx);
13616 if (!ROUTE_UNUSABLE(new_route)) {
13617 can_rebind = TRUE;
13618 }
13619 } else if (family == AF_INET6) {
13620 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13621 struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13622 dst6->sin6_family = AF_INET6;
13623 dst6->sin6_len = sizeof(struct sockaddr_in6);
13624 dst6->sin6_addr = ip6->ip6_dst;
13625 rtalloc_scoped(new_route, if_idx);
13626 if (!ROUTE_UNUSABLE(new_route)) {
13627 can_rebind = TRUE;
13628 }
13629 }
13630 }
13631
13632 return can_rebind;
13633 }
13634
13635 static bool
necp_addr_is_loopback(struct sockaddr * address)13636 necp_addr_is_loopback(struct sockaddr *address)
13637 {
13638 if (address == NULL) {
13639 return FALSE;
13640 }
13641
13642 if (address->sa_family == AF_INET) {
13643 return ntohl(SIN(address)->sin_addr.s_addr) == INADDR_LOOPBACK;
13644 } else if (address->sa_family == AF_INET6) {
13645 if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13646 return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13647 } else {
13648 // Match ::ffff:127.0.0.1 loopback address
13649 in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13650 return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13651 }
13652 }
13653
13654 return FALSE;
13655 }
13656
13657 static bool
necp_is_loopback(struct sockaddr * local_addr,struct sockaddr * remote_addr,struct inpcb * inp,struct mbuf * packet,u_int32_t bound_interface_index)13658 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13659 {
13660 // Note: This function only checks for the loopback addresses.
13661 // In the future, we may want to expand to also allow any traffic
13662 // going through the loopback interface, but until then, this
13663 // check is cheaper.
13664
13665 if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13666 return TRUE;
13667 }
13668
13669 if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13670 return TRUE;
13671 }
13672
13673 if (inp != NULL) {
13674 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13675 return TRUE;
13676 }
13677 if (inp->inp_vflag & INP_IPV4) {
13678 if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
13679 ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
13680 return TRUE;
13681 }
13682 } else if (inp->inp_vflag & INP_IPV6) {
13683 if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13684 IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13685 return TRUE;
13686 }
13687 }
13688 } else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13689 return TRUE;
13690 }
13691
13692 if (packet != NULL) {
13693 struct ip *ip = mtod(packet, struct ip *);
13694 if (ip->ip_v == 4) {
13695 if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
13696 return TRUE;
13697 }
13698 if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
13699 return TRUE;
13700 }
13701 } else if (ip->ip_v == 6) {
13702 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13703 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13704 return TRUE;
13705 }
13706 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13707 return TRUE;
13708 }
13709 }
13710 }
13711
13712 return FALSE;
13713 }
13714
13715 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13716 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13717 {
13718 if (inp != NULL) {
13719 if (!(inp->inp_vflag & INP_IPV6)) {
13720 return false;
13721 }
13722 if (INP_INTCOPROC_ALLOWED(inp)) {
13723 return true;
13724 }
13725 if ((inp->inp_flags & INP_BOUND_IF) &&
13726 IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13727 return true;
13728 }
13729 return false;
13730 }
13731 if (packet != NULL) {
13732 struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13733 struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13734 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13735 NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13736 return true;
13737 }
13738 }
13739
13740 return false;
13741 }
13742
13743 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13744 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13745 {
13746 char dest_str[MAX_IPv6_STR_LEN];
13747
13748 if (necp_drop_dest_debug > 0) {
13749 if (sau->sa.sa_family == AF_INET) {
13750 (void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13751 } else if (sau->sa.sa_family == AF_INET6) {
13752 (void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13753 } else {
13754 dest_str[0] = 0;
13755 }
13756 }
13757 for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13758 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13759 struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13760
13761 if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13762 if (necp_drop_dest_debug > 0) {
13763 char subnet_str[MAX_IPv6_STR_LEN];
13764 struct proc *p = current_proc();
13765 pid_t pid = proc_pid(p);
13766
13767 if (sau->sa.sa_family == AF_INET) {
13768 (void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13769 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);
13770 } else if (sau->sa.sa_family == AF_INET6) {
13771 (void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13772 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);
13773 }
13774 }
13775 return true;
13776 }
13777 }
13778 if (necp_drop_dest_debug > 1) {
13779 struct proc *p = current_proc();
13780 pid_t pid = proc_pid(p);
13781
13782 os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13783 }
13784 return false;
13785 }
13786
13787 static int
13788 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13789 {
13790 #pragma unused(arg1, arg2, oidp)
13791 int changed = 0;
13792 int error = 0;
13793 struct necp_drop_dest_policy tmp_drop_dest_policy;
13794 struct proc *p = current_proc();
13795 pid_t pid = proc_pid(p);
13796
13797 if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13798 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13799 NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13800 return EPERM;
13801 }
13802 if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13803 NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13804 return EINVAL;
13805 }
13806
13807 memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13808 error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13809 if (error != 0) {
13810 NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13811 return error;
13812 }
13813 if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13814 return error;
13815 }
13816
13817 //
13818 // Validate the passed parameters
13819 //
13820 if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13821 NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13822 return EINVAL;
13823 }
13824 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13825 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13826 struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13827
13828 switch (tmp_drop_dest_entry->level) {
13829 case NECP_SESSION_PRIORITY_UNKNOWN:
13830 if (tmp_drop_dest_policy.entry_count != 0) {
13831 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);
13832 return EINVAL;
13833 }
13834 break;
13835 case NECP_SESSION_PRIORITY_CONTROL:
13836 case NECP_SESSION_PRIORITY_CONTROL_1:
13837 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13838 case NECP_SESSION_PRIORITY_HIGH:
13839 case NECP_SESSION_PRIORITY_HIGH_1:
13840 case NECP_SESSION_PRIORITY_HIGH_2:
13841 case NECP_SESSION_PRIORITY_HIGH_3:
13842 case NECP_SESSION_PRIORITY_HIGH_4:
13843 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13844 case NECP_SESSION_PRIORITY_DEFAULT:
13845 case NECP_SESSION_PRIORITY_LOW:
13846 if (tmp_drop_dest_policy.entry_count == 0) {
13847 NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13848 return EINVAL;
13849 }
13850 break;
13851 default: {
13852 NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13853 return EINVAL;
13854 }
13855 }
13856
13857 switch (npca->address.sa.sa_family) {
13858 case AF_INET: {
13859 if (npca->prefix > 32) {
13860 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13861 return EINVAL;
13862 }
13863 if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
13864 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
13865 return EINVAL;
13866 }
13867 if (npca->address.sin.sin_port != 0) {
13868 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);
13869 return EINVAL;
13870 }
13871 break;
13872 }
13873 case AF_INET6: {
13874 if (npca->prefix > 128) {
13875 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13876 return EINVAL;
13877 }
13878 if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
13879 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
13880 return EINVAL;
13881 }
13882 if (npca->address.sin6.sin6_port != 0) {
13883 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);
13884 return EINVAL;
13885 }
13886 if (npca->address.sin6.sin6_flowinfo != 0) {
13887 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);
13888 return EINVAL;
13889 }
13890 if (npca->address.sin6.sin6_scope_id != 0) {
13891 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);
13892 return EINVAL;
13893 }
13894 break;
13895 }
13896 default: {
13897 return EINVAL;
13898 }
13899 }
13900 }
13901
13902 //
13903 // Commit the changed policy
13904 //
13905 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
13906 memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
13907
13908 necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
13909 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13910 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13911 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13912
13913 memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
13914
13915 necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
13916 }
13917 lck_rw_done(&necp_kernel_policy_lock);
13918
13919 return 0;
13920 }
13921
13922 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])13923 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
13924 {
13925 uint16_t fam = address->sa.sa_family;
13926 memset(addr_str, 0, MAX_IPv6_STR_LEN);
13927 if (fam == AF_INET) {
13928 (void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
13929 } else if (fam == AF_INET6) {
13930 (void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
13931 }
13932 return __unsafe_null_terminated_from_indexable(addr_str);
13933 }
13934