1 /*
2 * Copyright (c) 2013-2024 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 (rt->rt_ifp->if_type == IFT_CELLULAR) {
8687 struct if_cellular_status_v1 *ifsr;
8688
8689 ifnet_lock_shared(rt->rt_ifp);
8690 lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8691
8692 if (rt->rt_ifp->if_link_status != NULL) {
8693 ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8694
8695 if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8696 if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8697 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8698 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8699 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8700 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8701 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8702 }
8703 }
8704 }
8705 lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8706 ifnet_lock_done(rt->rt_ifp);
8707 }
8708
8709 // Check link quality
8710 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8711 (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8712 rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8713 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8714 }
8715
8716 // Check QoS marking (fastlane)
8717 for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8718 if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8719 *flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8720 // If the route can use QoS markings, stop iterating route rules
8721 break;
8722 }
8723 }
8724
8725 if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8726 *flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8727 }
8728
8729 if (traffic_class == SO_TC_BK_SYS) {
8730 // Block BK_SYS traffic if interface is throttled
8731 u_int32_t throttle_level = 0;
8732 if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8733 if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8734 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8735 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8736 }
8737 }
8738 }
8739 }
8740 }
8741
8742 u_int interface_to_check = returned_result->routed_interface_index;
8743 if (interface_to_check == 0) {
8744 interface_to_check = output_bound_interface;
8745 }
8746 union necp_sockaddr_union default_address;
8747 struct rtentry *v4Route = NULL;
8748 struct rtentry *v6Route = NULL;
8749
8750 memset(&default_address, 0, sizeof(default_address));
8751
8752 // Reset address to 0.0.0.0
8753 default_address.sa.sa_family = AF_INET;
8754 default_address.sa.sa_len = sizeof(struct sockaddr_in);
8755 v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8756 returned_result->routed_interface_index);
8757
8758 // Reset address to ::
8759 default_address.sa.sa_family = AF_INET6;
8760 default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8761 v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8762 returned_result->routed_interface_index);
8763
8764 if (v4Route != NULL) {
8765 if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8766 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8767 }
8768 if (returned_v4_gateway != NULL &&
8769 v4Route->rt_gateway != NULL &&
8770 v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8771 memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8772 memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8773 }
8774 rtfree(v4Route);
8775 v4Route = NULL;
8776 }
8777
8778 if (v6Route != NULL) {
8779 if (v6Route->rt_ifp != NULL) {
8780 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8781
8782 if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8783 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8784 }
8785 }
8786 if (returned_v6_gateway != NULL &&
8787 v6Route->rt_gateway != NULL &&
8788 v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8789 SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8790 }
8791 rtfree(v6Route);
8792 v6Route = NULL;
8793 }
8794 }
8795
8796 // Take two passes through the rule list: first for rules that don't match based on agents,
8797 // second for rules that match based on agents. Since rules can modify the agent list itself,
8798 // this makes the logic more deterministic. This allows a non-agent matching rule to remove
8799 // an agent before it is used for matching later.
8800 size_t route_rule_index = 0;
8801 bool second_pass = false;
8802 while (route_rule_index < route_rule_id_array_count) {
8803 bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8804 if (rule_matches_agents != second_pass) {
8805 // Process rules that match based on agents only in the second pass
8806 route_rule_index++;
8807 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8808 route_rule_index = 0;
8809 second_pass = true;
8810 }
8811 continue;
8812 }
8813
8814 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8815 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);
8816 if (!route_is_allowed) {
8817 // If the route is blocked, treat the lookup as a drop
8818 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8819 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8820
8821 if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8822 if (reason != NULL) {
8823 if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8824 *reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8825 } else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8826 *reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8827 }
8828 }
8829 necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8830 }
8831 // If the route gets denied, stop matching rules
8832 break;
8833 }
8834
8835 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8836 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8837 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8838 route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8839 if (flow_divert_control_unit != 0) {
8840 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8841 returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8842 }
8843 if (flow_divert_aggregate_unit != 0) {
8844 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8845 }
8846 }
8847
8848 // Check if there is a route rule that adds or removes an agent
8849 bool remove = false;
8850 u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8851 if (netagent_id != 0) {
8852 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8853 if (mapping != NULL) {
8854 bool agent_already_present = false;
8855 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8856 if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8857 // Found the agent already present
8858 agent_already_present = true;
8859 if (remove) {
8860 // Mark as remove if necessary
8861 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8862 }
8863 } else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8864 // Found open slot
8865 if (!agent_already_present) {
8866 uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8867 if (remove) {
8868 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8869 } else {
8870 returned_result->netagent_use_flags[netagent_cursor] = 0;
8871 }
8872 }
8873 break;
8874 }
8875 }
8876 }
8877
8878 // Update the local netagent_ids array for future evaluations
8879 if (remove) {
8880 // Check if the agent ID is in the array, and remove it
8881 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8882 if (netagent_id == netagent_ids[netagent_cursor]) {
8883 netagent_ids[netagent_cursor] = 0;
8884 }
8885 }
8886 } else {
8887 // Check if the agent ID is not yet in the array, and add it
8888 bool found = false;
8889 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8890 if (netagent_id == netagent_ids[netagent_cursor]) {
8891 found = true;
8892 break;
8893 }
8894 }
8895 if (!found) {
8896 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8897 if (netagent_ids[netagent_cursor] == 0) {
8898 // Empty slot, add the agent
8899 netagent_ids[netagent_cursor] = netagent_id;
8900 break;
8901 }
8902 }
8903 }
8904 }
8905 }
8906
8907 route_rule_index++;
8908 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8909 route_rule_index = 0;
8910 second_pass = true;
8911 }
8912 }
8913
8914 if (rt != NULL && rt->rt_ifp != NULL) {
8915 const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8916 const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8917 const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8918 IFNET_IS_EXPENSIVE(rt->rt_ifp));
8919 const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8920 IFNET_IS_CONSTRAINED(rt->rt_ifp));
8921 const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
8922 IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
8923 !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT)));
8924
8925 const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
8926 if (!is_listener && !is_browser) {
8927 if (reason != NULL) {
8928 if (expensive_prohibited) {
8929 *reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8930 } else if (constrained_prohibited) {
8931 *reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8932 } else if (ultra_constrained_not_allowed) {
8933 *reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8934 }
8935 }
8936 if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
8937 // If a property of the interface was not allowed, treat it as a drop
8938 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8939 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8940 }
8941 }
8942 }
8943
8944 if (rt != NULL) {
8945 if (returned_route != NULL) {
8946 *returned_route = rt;
8947 } else {
8948 rtfree(rt);
8949 }
8950 rt = NULL;
8951 }
8952
8953 done:
8954 // Unlock
8955 lck_rw_done(&necp_kernel_policy_lock);
8956
8957 if (release_eproc && effective_proc != PROC_NULL) {
8958 proc_rele(effective_proc);
8959 }
8960 #if defined(XNU_TARGET_OS_OSX)
8961 if (responsible_proc != PROC_NULL) {
8962 proc_rele(responsible_proc);
8963 }
8964 #endif
8965
8966 if (cred != NULL) {
8967 kauth_cred_unref(&cred);
8968 }
8969
8970 return error;
8971 }
8972
8973 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)8974 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
8975 {
8976 struct rtentry *rt = NULL;
8977 bool is_local = FALSE;
8978
8979 if (remote_addr == NULL) {
8980 return NULL;
8981 }
8982
8983 if (remote_addr->sa.sa_len == 0 ||
8984 (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8985 (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8986 return FALSE;
8987 }
8988
8989 // Lookup route regardless of the scoped interface to check if
8990 // remote address is in a local network.
8991 rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
8992
8993 if (rt == NULL) {
8994 goto done;
8995 }
8996 if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
8997 goto free_rt;
8998 }
8999 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
9000
9001 free_rt:
9002 rtfree(rt);
9003
9004 done:
9005 return is_local;
9006 }
9007
9008 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)9009 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
9010 necp_app_id app_id,
9011 necp_app_id real_app_id,
9012 uint8_t is_entitled,
9013 u_int32_t account_id,
9014 struct substring domain,
9015 u_int8_t domain_dot_count,
9016 const char *url __null_terminated,
9017 pid_t pid,
9018 int32_t pid_version,
9019 uid_t uid,
9020 uid_t real_uid,
9021 u_int32_t bound_interface_index,
9022 u_int32_t traffic_class,
9023 u_int16_t protocol,
9024 union necp_sockaddr_union *local,
9025 union necp_sockaddr_union *remote,
9026 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9027 u_int32_t num_required_agent_types,
9028 bool has_client,
9029 uint32_t client_flags,
9030 int is_platform_binary,
9031 bool has_signed_result,
9032 proc_t proc,
9033 u_int16_t pf_tag,
9034 u_int16_t scheme_port,
9035 struct rtentry *rt,
9036 bool is_loopback,
9037 int debug,
9038 bool real_is_platform_binary,
9039 u_int32_t bound_interface_flags,
9040 u_int32_t bound_interface_eflags,
9041 u_int32_t bound_interface_xflags,
9042 struct necp_socket_info *info,
9043 bool is_delegated,
9044 struct socket *socket)
9045 {
9046 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9047 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9048 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9049 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9050 "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
9051 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9052 if (bound_interface_index == cond_bound_interface_index) {
9053 // No match, matches forbidden interface
9054 return FALSE;
9055 }
9056 } else {
9057 if (bound_interface_index != cond_bound_interface_index) {
9058 // No match, does not match required interface
9059 return FALSE;
9060 }
9061 }
9062 }
9063 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9064 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9065 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9066 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9067 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9068 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9069 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9070 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9071 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9072 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9073 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9074 // No match, matches some forbidden interface flags
9075 return FALSE;
9076 }
9077 } else {
9078 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9079 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9080 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9081 // No match, does not match some required interface xflags
9082 return FALSE;
9083 }
9084 }
9085 }
9086 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9087 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9088 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
9089 if (bound_interface_index != 0) {
9090 // No match, requires a non-bound packet
9091 return FALSE;
9092 }
9093 }
9094 }
9095
9096 if (kernel_policy->condition_mask == 0) {
9097 return TRUE;
9098 }
9099
9100 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9101 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
9102 "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
9103 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
9104 if (app_id == kernel_policy->cond_app_id) {
9105 // No match, matches forbidden application
9106 return FALSE;
9107 }
9108 } else {
9109 if (app_id != kernel_policy->cond_app_id) {
9110 // No match, does not match required application
9111 return FALSE;
9112 }
9113 }
9114
9115 // Check signing identifier only after APP ID matched
9116 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
9117 kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9118 u_int8_t matched = necp_boolean_state_false;
9119 const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
9120 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
9121 "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
9122 kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
9123 signing_id ? signing_id : "<n/a>");
9124 if (signing_id != NULL) {
9125 if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
9126 matched = necp_boolean_state_true;
9127 }
9128 }
9129
9130 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9131 if (matched == necp_boolean_state_true) {
9132 return FALSE;
9133 }
9134 } else {
9135 if (matched != necp_boolean_state_true) {
9136 return FALSE;
9137 }
9138 }
9139 }
9140 }
9141
9142 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9143 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
9144 "NECP_KERNEL_CONDITION_REAL_APP_ID",
9145 kernel_policy->cond_real_app_id, real_app_id);
9146 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9147 if (real_app_id == kernel_policy->cond_real_app_id) {
9148 // No match, matches forbidden application
9149 return FALSE;
9150 }
9151 } else {
9152 if (real_app_id != kernel_policy->cond_real_app_id) {
9153 // No match, does not match required application
9154 return FALSE;
9155 }
9156 }
9157 }
9158
9159 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9160 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
9161 if (!has_client) {
9162 return FALSE;
9163 }
9164 }
9165
9166 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9167 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
9168 if (!is_entitled) {
9169 // Process is missing entitlement
9170 return FALSE;
9171 }
9172 }
9173
9174 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9175 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);
9176 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9177 if (is_platform_binary) {
9178 // Process is platform binary
9179 return FALSE;
9180 }
9181 } else {
9182 if (!is_platform_binary) {
9183 // Process is not platform binary
9184 return FALSE;
9185 }
9186 }
9187 }
9188
9189 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9190 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
9191 if (has_signed_result == 0) {
9192 // Client did not have a system-signed result
9193 return FALSE;
9194 }
9195 }
9196
9197 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
9198 if (proc != NULL) {
9199 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
9200 kernel_policy->cond_sdk_version.platform,
9201 kernel_policy->cond_sdk_version.min_version,
9202 kernel_policy->cond_sdk_version.version,
9203 proc_platform(proc),
9204 proc_min_sdk(proc),
9205 proc_sdk(proc));
9206 if (kernel_policy->cond_sdk_version.platform != 0) {
9207 if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
9208 // Process does not match platform
9209 return FALSE;
9210 }
9211 }
9212
9213 if (kernel_policy->cond_sdk_version.min_version != 0) {
9214 if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
9215 // Process min version is older than required min version
9216 return FALSE;
9217 }
9218 }
9219
9220 if (kernel_policy->cond_sdk_version.version != 0) {
9221 if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
9222 // Process SDK version is older than required version
9223 return FALSE;
9224 }
9225 }
9226 }
9227 }
9228
9229 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
9230 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
9231 if (kernel_policy->cond_custom_entitlement != NULL) {
9232 if (proc == NULL) {
9233 // No process found, cannot check entitlement
9234 return FALSE;
9235 }
9236 task_t __single task = proc_task(proc);
9237 if (task == NULL ||
9238 !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
9239 // Process is missing custom entitlement
9240 return FALSE;
9241 }
9242 }
9243 }
9244
9245 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9246 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
9247 "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
9248 // Exact match requires the number of dots to match (no suffix matching allowed)
9249 bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
9250 necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
9251 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9252 if (domain_matches) {
9253 // No match, matches forbidden domain
9254 return FALSE;
9255 }
9256 } else {
9257 if (!domain_matches) {
9258 // No match, does not match required domain
9259 return FALSE;
9260 }
9261 }
9262 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9263 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
9264 "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
9265 bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
9266 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9267 if (domain_matches) {
9268 // No match, matches forbidden domain
9269 return FALSE;
9270 }
9271 } else {
9272 if (!domain_matches) {
9273 // No match, does not match required domain
9274 return FALSE;
9275 }
9276 }
9277 }
9278
9279 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9280 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9281 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (ID)", kernel_policy->cond_domain_filter, 0);
9282 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9283 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (domain)", "<n/a>", domain.string);
9284 bool domain_matches = false;
9285 if (NECP_IS_DOMAIN_FILTER_ID(kernel_policy->cond_domain_filter)) {
9286 struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
9287 if (filter != NULL && filter->filter != NULL) {
9288 domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
9289 }
9290 } else {
9291 domain_matches = necp_match_domain_with_trie(&necp_global_domain_trie_list, kernel_policy->cond_domain_filter, domain.string, domain.length);
9292 if (debug) {
9293 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);
9294 }
9295 }
9296 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9297 if (domain_matches) {
9298 // No match, matches forbidden domain
9299 return FALSE;
9300 }
9301 } else {
9302 if (!domain_matches) {
9303 // No match, does not match required domain
9304 return FALSE;
9305 }
9306 }
9307 }
9308
9309 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
9310 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
9311 "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
9312 bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
9313 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
9314 if (url_matches) {
9315 // No match, matches forbidden url
9316 return FALSE;
9317 }
9318 } else {
9319 if (!url_matches) {
9320 // No match, does not match required url
9321 return FALSE;
9322 }
9323 }
9324 }
9325
9326 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9327 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
9328 "NECP_KERNEL_CONDITION_ACCOUNT_ID",
9329 kernel_policy->cond_account_id, account_id);
9330 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9331 if (account_id == kernel_policy->cond_account_id) {
9332 // No match, matches forbidden account
9333 return FALSE;
9334 }
9335 } else {
9336 if (account_id != kernel_policy->cond_account_id) {
9337 // No match, does not match required account
9338 return FALSE;
9339 }
9340 }
9341 }
9342
9343 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
9344 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
9345 "NECP_KERNEL_CONDITION_PID",
9346 kernel_policy->cond_pid, pid);
9347 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
9348 if (pid == kernel_policy->cond_pid) {
9349 // No match, matches forbidden pid
9350 return FALSE;
9351 }
9352 if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
9353 return FALSE;
9354 }
9355 } else {
9356 if (pid != kernel_policy->cond_pid) {
9357 // No match, does not match required pid
9358 return FALSE;
9359 }
9360 if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
9361 return FALSE;
9362 }
9363 }
9364 }
9365
9366 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9367 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9368 "NECP_KERNEL_CONDITION_UID",
9369 kernel_policy->cond_uid, uid);
9370 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9371 if (uid == kernel_policy->cond_uid) {
9372 // No match, matches forbidden uid
9373 return FALSE;
9374 }
9375 } else {
9376 if (uid != kernel_policy->cond_uid) {
9377 // No match, does not match required uid
9378 return FALSE;
9379 }
9380 }
9381 }
9382
9383 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9384 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9385 "NECP_KERNEL_CONDITION_REAL_UID",
9386 kernel_policy->cond_real_uid, real_uid);
9387 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9388 if (real_uid == kernel_policy->cond_real_uid) {
9389 // No match, matches forbidden uid
9390 return FALSE;
9391 }
9392 } else {
9393 if (real_uid != kernel_policy->cond_real_uid) {
9394 // No match, does not match required uid
9395 return FALSE;
9396 }
9397 }
9398 }
9399
9400 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9401 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9402 kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9403 traffic_class, 0, 0);
9404 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9405 if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9406 traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9407 // No match, matches forbidden traffic class
9408 return FALSE;
9409 }
9410 } else {
9411 if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9412 traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9413 // No match, does not match required traffic class
9414 return FALSE;
9415 }
9416 }
9417 }
9418
9419 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9420 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9421 "NECP_KERNEL_CONDITION_PROTOCOL",
9422 kernel_policy->cond_protocol, protocol);
9423 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9424 if (protocol == kernel_policy->cond_protocol) {
9425 // No match, matches forbidden protocol
9426 return FALSE;
9427 }
9428 } else {
9429 if (protocol != kernel_policy->cond_protocol) {
9430 // No match, does not match required protocol
9431 return FALSE;
9432 }
9433 }
9434 }
9435
9436 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9437 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9438 kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9439 "n/a", "n/a", "n/a");
9440 bool matches_agent_type = FALSE;
9441 for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9442 struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9443 if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9444 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) &&
9445 (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9446 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)) {
9447 // Found a required agent that matches
9448 matches_agent_type = TRUE;
9449 break;
9450 }
9451 }
9452 if (!matches_agent_type) {
9453 return FALSE;
9454 }
9455 }
9456
9457 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9458 bool is_local = FALSE;
9459 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9460
9461 if (rt != NULL) {
9462 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9463 } else {
9464 is_local = necp_is_route_local(remote, include_local_addresses);
9465 }
9466 if (info != NULL) {
9467 info->is_local = is_local;
9468 }
9469
9470 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);
9471 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9472 if (is_local) {
9473 // Match local-networks, fail
9474 return FALSE;
9475 }
9476 } else {
9477 if (!is_local) {
9478 // Either no route to validate or no match for local networks
9479 return FALSE;
9480 }
9481 }
9482 }
9483
9484 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9485 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9486 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9487 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9488 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9489 if (inRange) {
9490 return FALSE;
9491 }
9492 } else {
9493 if (!inRange) {
9494 return FALSE;
9495 }
9496 }
9497 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9498 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9499 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);
9500 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9501 if (inSubnet) {
9502 return FALSE;
9503 }
9504 } else {
9505 if (!inSubnet) {
9506 return FALSE;
9507 }
9508 }
9509 }
9510 }
9511
9512 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9513 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9514 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9515 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9516 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9517 if (inRange) {
9518 return FALSE;
9519 }
9520 } else {
9521 if (!inRange) {
9522 return FALSE;
9523 }
9524 }
9525 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9526 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9527 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);
9528 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9529 if (inSubnet) {
9530 return FALSE;
9531 }
9532 } else {
9533 if (!inSubnet) {
9534 return FALSE;
9535 }
9536 }
9537 }
9538 }
9539
9540 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9541 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9542 "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9543 kernel_policy->cond_client_flags, client_flags);
9544 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9545 if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9546 // Flags do match, and condition is negative, fail.
9547 return FALSE;
9548 }
9549 } else {
9550 if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9551 // Flags do not match, fail.
9552 return FALSE;
9553 }
9554 }
9555 }
9556
9557 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9558 bool isEmpty = necp_addr_is_empty(SA(local));
9559 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9560 "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9561 0, isEmpty);
9562 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9563 if (isEmpty) {
9564 return FALSE;
9565 }
9566 } else {
9567 if (!isEmpty) {
9568 return FALSE;
9569 }
9570 }
9571 }
9572
9573 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9574 bool isEmpty = necp_addr_is_empty(SA(remote));
9575 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9576 "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9577 0, isEmpty);
9578 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9579 if (isEmpty) {
9580 return FALSE;
9581 }
9582 } else {
9583 if (!isEmpty) {
9584 return FALSE;
9585 }
9586 }
9587 }
9588
9589 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9590 u_int16_t remote_port = 0;
9591 if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9592 remote_port = SIN(remote)->sin_port;
9593 }
9594 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9595 "NECP_KERNEL_CONDITION_SCHEME_PORT",
9596 scheme_port, remote_port);
9597 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9598 if (kernel_policy->cond_scheme_port == scheme_port ||
9599 kernel_policy->cond_scheme_port == remote_port) {
9600 return FALSE;
9601 }
9602 } else {
9603 if (kernel_policy->cond_scheme_port != scheme_port &&
9604 kernel_policy->cond_scheme_port != remote_port) {
9605 return FALSE;
9606 }
9607 }
9608 }
9609
9610 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9611 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9612 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9613 kernel_policy->cond_packet_filter_tags,
9614 pf_tag);
9615 bool tags_matched = false;
9616 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9617 if (pf_tag == PF_TAG_ID_STACK_DROP) {
9618 tags_matched = true;
9619 }
9620 }
9621
9622 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9623 if (tags_matched) {
9624 return FALSE;
9625 }
9626 } else {
9627 if (!tags_matched) {
9628 return FALSE;
9629 }
9630 }
9631 }
9632
9633 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9634 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9635 "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9636 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9637 if (is_loopback) {
9638 return FALSE;
9639 }
9640 } else {
9641 if (!is_loopback) {
9642 return FALSE;
9643 }
9644 }
9645 }
9646
9647 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9648 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9649 "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9650 if (is_delegated) {
9651 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9652 if (real_is_platform_binary) {
9653 return FALSE;
9654 }
9655 } else {
9656 if (!real_is_platform_binary) {
9657 return FALSE;
9658 }
9659 }
9660 } else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9661 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9662 // If the connection is not delegated, and the policy did not specify a particular effective process UUID
9663 // or PID, check the process directly
9664 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9665 if (is_platform_binary) {
9666 return FALSE;
9667 }
9668 } else {
9669 if (!is_platform_binary) {
9670 return FALSE;
9671 }
9672 }
9673 }
9674 }
9675
9676 return TRUE;
9677 }
9678
9679 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9680 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9681 {
9682 return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9683 }
9684
9685 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)9686 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)
9687 {
9688 struct socket *so = NULL;
9689 proc_t sock_proc = NULL;
9690 proc_t curr_proc = current_proc();
9691
9692 memset(info, 0, sizeof(struct necp_socket_info));
9693
9694 so = inp->inp_socket;
9695
9696 info->drop_order = drop_order;
9697 info->is_loopback = is_loopback;
9698 info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9699
9700 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9701 necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9702 info->uid = kauth_cred_getuid(so->so_cred);
9703 info->real_uid = info->uid;
9704 }
9705
9706 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9707 info->traffic_class = so->so_traffic_class;
9708 }
9709
9710 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9711 info->has_client = !uuid_is_null(inp->necp_client_uuid);
9712 }
9713
9714 if (inp->inp_ip_p) {
9715 info->protocol = inp->inp_ip_p;
9716 } else {
9717 info->protocol = SOCK_PROTO(so);
9718 }
9719
9720 if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9721 u_int32_t responsible_application_id = 0;
9722
9723 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9724 if (existing_mapping) {
9725 info->application_id = existing_mapping->id;
9726 }
9727
9728 #if defined(XNU_TARGET_OS_OSX)
9729 if (so->so_rpid > 0) {
9730 existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9731 if (existing_mapping != NULL) {
9732 responsible_application_id = existing_mapping->id;
9733 }
9734 }
9735 #endif
9736
9737 if (responsible_application_id > 0) {
9738 info->real_application_id = info->application_id;
9739 info->application_id = responsible_application_id;
9740 info->used_responsible_pid = true;
9741 } else if (!(so->so_flags & SOF_DELEGATED)) {
9742 info->real_application_id = info->application_id;
9743 } else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9744 struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9745 if (real_existing_mapping) {
9746 info->real_application_id = real_existing_mapping->id;
9747 }
9748 }
9749 }
9750
9751 pid_t socket_pid =
9752 #if defined(XNU_TARGET_OS_OSX)
9753 info->used_responsible_pid ? so->so_rpid :
9754 #endif
9755 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9756 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9757 sock_proc = proc_find(socket_pid);
9758 if (socket_proc) {
9759 *socket_proc = sock_proc;
9760 }
9761 }
9762
9763 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9764 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9765 info->is_entitled = necp_task_has_match_entitlement(task);
9766 if (!info->is_entitled) {
9767 // Task does not have entitlement, check the parent task
9768 necp_get_parent_is_entitled(task, info);
9769 }
9770 }
9771
9772 info->pid = socket_pid;
9773 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9774 info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9775 }
9776
9777 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9778 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9779 if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9780 info->is_platform_binary = true;
9781 } else if (so->so_rpid != 0) {
9782 proc_t responsible_proc = proc_find(so->so_rpid);
9783 if (responsible_proc != NULL) {
9784 if (necp_is_platform_binary(responsible_proc)) {
9785 info->is_platform_binary = true;
9786 info->used_responsible_pid = true;
9787 }
9788 proc_rele(responsible_proc);
9789 }
9790 }
9791 }
9792
9793 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9794 proc_t real_proc = curr_proc;
9795 bool release_real_proc = false;
9796 if (so->last_pid != proc_pid(real_proc)) {
9797 if (so->last_pid == socket_pid && sock_proc != NULL) {
9798 real_proc = sock_proc;
9799 } else {
9800 proc_t last_proc = proc_find(so->last_pid);
9801 if (last_proc != NULL) {
9802 real_proc = last_proc;
9803 release_real_proc = true;
9804 }
9805 }
9806 }
9807 if (real_proc != NULL) {
9808 if (real_proc == kernproc) {
9809 info->real_is_platform_binary = true;
9810 } else {
9811 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9812 }
9813 if (release_real_proc) {
9814 proc_rele(real_proc);
9815 }
9816 }
9817 }
9818
9819 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9820 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9821 if (existing_mapping) {
9822 info->account_id = existing_mapping->id;
9823 }
9824 }
9825
9826 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9827 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9828 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9829 info->domain = inp->inp_necp_attributes.inp_domain;
9830 }
9831
9832 if (override_bound_interface) {
9833 info->bound_interface_index = override_bound_interface;
9834 } else {
9835 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9836 info->bound_interface_index = inp->inp_boundifp->if_index;
9837 }
9838 }
9839
9840 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9841 info->bound_interface_index != IFSCOPE_NONE) {
9842 ifnet_head_lock_shared();
9843 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9844 if (interface != NULL) {
9845 info->bound_interface_flags = interface->if_flags;
9846 info->bound_interface_eflags = interface->if_eflags;
9847 info->bound_interface_xflags = interface->if_xflags;
9848 }
9849 ifnet_head_done();
9850 }
9851
9852 bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9853 uuid_is_null(inp->necp_client_uuid) &&
9854 necp_socket_has_resolver_signature(inp));
9855 if ((necp_data_tracing_level && necp_data_tracing_port) ||
9856 necp_restrict_multicast ||
9857 needs_address_for_signature ||
9858 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) ||
9859 (IS_INET(so) && IS_UDP(so))) {
9860 if (override_local_addr != NULL) {
9861 if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9862 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9863 if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9864 struct sockaddr_in sin;
9865 in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9866 memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9867 memcpy(&info->local_addr, &sin, sin.sin_len);
9868 }
9869 } else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9870 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9871 }
9872 } else {
9873 if (inp->inp_vflag & INP_IPV6) {
9874 SIN6(&info->local_addr)->sin6_family = AF_INET6;
9875 SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9876 SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9877 memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9878 } else if (inp->inp_vflag & INP_IPV4) {
9879 SIN(&info->local_addr)->sin_family = AF_INET;
9880 SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9881 SIN(&info->local_addr)->sin_port = inp->inp_lport;
9882 memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9883 }
9884 }
9885
9886 if (override_remote_addr != NULL) {
9887 if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9888 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9889 if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9890 struct sockaddr_in sin;
9891 in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9892 memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9893 memcpy(&info->remote_addr, &sin, sin.sin_len);
9894 }
9895 } else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9896 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9897 }
9898 } else {
9899 if (inp->inp_vflag & INP_IPV6) {
9900 SIN6(&info->remote_addr)->sin6_family = AF_INET6;
9901 SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9902 SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
9903 memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
9904 } else if (inp->inp_vflag & INP_IPV4) {
9905 SIN(&info->remote_addr)->sin_family = AF_INET;
9906 SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9907 SIN(&info->remote_addr)->sin_port = inp->inp_fport;
9908 memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
9909 }
9910 }
9911 // Clear the embedded scope id from v6 addresses
9912 if (info->local_addr.sa.sa_family == AF_INET6) {
9913 struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
9914 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9915 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9916 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9917 sin6->sin6_addr.s6_addr16[1] = 0;
9918 }
9919 }
9920 }
9921 if (info->remote_addr.sa.sa_family == AF_INET6) {
9922 struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
9923 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9924 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9925 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9926 sin6->sin6_addr.s6_addr16[1] = 0;
9927 }
9928 }
9929 }
9930 }
9931
9932 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9933 // For checking sockets, only validate that there is an NECP client present. It will have
9934 // already checked for the signature.
9935 if (!uuid_is_null(inp->necp_client_uuid)) {
9936 info->has_system_signed_result = true;
9937 } else {
9938 info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
9939 }
9940 }
9941
9942 if (IS_INET(so) && IS_UDP(so)) {
9943 info->soflow_entry = soflow_get_flow(so, &(info->local_addr.sa), &(info->remote_addr.sa), NULL, 0, override_direction, input_ifindex);
9944 } else {
9945 info->soflow_entry = NULL;
9946 }
9947
9948 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9949 info->client_flags = 0;
9950 if (INP_NO_CONSTRAINED(inp)) {
9951 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
9952 }
9953 if (INP_NO_EXPENSIVE(inp)) {
9954 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
9955 }
9956 if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
9957 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
9958 }
9959 if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
9960 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
9961 }
9962 if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
9963 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
9964 }
9965 if (IS_INET(so) && IS_UDP(so)) {
9966 // If the socket has a flow entry for this 4-tuple then check if the flow is outgoing
9967 // and set the inbound flag accordingly. Otherwise use the direction to set the inbound flag.
9968 if (info->soflow_entry != NULL) {
9969 if (!info->soflow_entry->soflow_outgoing) {
9970 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9971 }
9972 } else if (override_direction == SOFLOW_DIRECTION_INBOUND) {
9973 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9974 }
9975 } else {
9976 // If the socket is explicitly marked as inbound then set the inbound flag.
9977 if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
9978 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9979 }
9980 }
9981 if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
9982 inp->inp_flags2 & INP2_EXTERNAL_PORT) {
9983 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
9984 }
9985 if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
9986 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
9987 }
9988 if (inp->inp_socket->so_options & SO_REUSEPORT) {
9989 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
9990 }
9991 }
9992 }
9993
9994 #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)
9995
9996 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)9997 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
9998 struct necp_socket_info *info,
9999 necp_kernel_policy_filter *return_filter,
10000 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
10001 size_t *return_route_rule_id_array_count,
10002 size_t route_rule_id_array_count,
10003 necp_kernel_policy_result *return_service_action,
10004 necp_kernel_policy_service *return_service,
10005 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
10006 size_t netagent_array_count,
10007 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
10008 size_t netagent_use_flags_array_count,
10009 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
10010 u_int32_t num_required_agent_types,
10011 proc_t proc,
10012 u_int16_t pf_tag,
10013 necp_kernel_policy_id *skip_policy_id,
10014 struct rtentry *rt,
10015 necp_kernel_policy_result *return_drop_dest_policy_result,
10016 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
10017 u_int32_t *return_flow_divert_aggregate_unit,
10018 struct socket *so,
10019 int debug)
10020 {
10021 struct necp_kernel_socket_policy *matched_policy = NULL;
10022 u_int32_t skip_order = 0;
10023 u_int32_t skip_session_order = 0;
10024 bool skipped_ip_result = false;
10025 size_t route_rule_id_count = 0;
10026 int i;
10027 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10028 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
10029 memset(&netagent_ids, 0, sizeof(netagent_ids));
10030 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
10031 size_t netagent_cursor = 0;
10032 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10033 size_t netagent_array_count_adjusted = netagent_array_count;
10034 if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
10035 netagent_array_count_adjusted = netagent_use_flags_array_count;
10036 }
10037
10038 if (return_drop_all_bypass != NULL) {
10039 *return_drop_all_bypass = drop_all_bypass;
10040 }
10041
10042 if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
10043 netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
10044 }
10045
10046 // Pre-process domain for quick matching
10047 struct substring domain_substring = {};
10048 u_int8_t domain_dot_count = 0;
10049 if (info->domain != NULL) {
10050 domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
10051 domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
10052 }
10053
10054 if (return_filter != NULL) {
10055 *return_filter = 0;
10056 }
10057
10058 if (return_route_rule_id_array_count != NULL) {
10059 *return_route_rule_id_array_count = 0;
10060 }
10061
10062 if (return_service_action != NULL) {
10063 *return_service_action = 0;
10064 }
10065
10066 if (return_service != NULL) {
10067 return_service->identifier = 0;
10068 return_service->data = 0;
10069 }
10070
10071 // Do not subject layer-2 filter to NECP policies, return a PASS policy
10072 if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
10073 return &pass_policy;
10074 }
10075
10076 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10077
10078 if (policy_search_array != NULL) {
10079 for (i = 0; policy_search_array[i] != NULL; i++) {
10080 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
10081
10082 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10083 // We've hit a drop all rule
10084 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10085 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
10086 if (return_drop_all_bypass != NULL) {
10087 *return_drop_all_bypass = drop_all_bypass;
10088 }
10089 }
10090 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10091 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
10092 break;
10093 }
10094 }
10095 if (necp_drop_dest_policy.entry_count != 0 &&
10096 necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
10097 // We've hit a drop by destination address rule
10098 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10099 break;
10100 }
10101 if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
10102 // We've hit a drop order for this socket
10103 break;
10104 }
10105 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10106 // Done skipping
10107 skip_order = 0;
10108 skip_session_order = 0;
10109 // If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
10110 if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
10111 *skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10112 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
10113 }
10114 }
10115 if (skip_order) {
10116 if (policy_search_array[i]->order < skip_order) {
10117 // Skip this policy
10118 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10119 // didn't, clear out the return value for skip ID when we are done with each session.'
10120 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10121 skipped_ip_result = true;
10122 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10123 }
10124 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
10125 continue;
10126 } else {
10127 // Done skipping
10128 skip_order = 0;
10129 skip_session_order = 0;
10130 }
10131 } else if (skip_session_order) {
10132 // Skip this policy
10133 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10134 // didn't, clear out the return value for skip ID when we are done with each session.'
10135 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10136 skipped_ip_result = true;
10137 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10138 }
10139 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
10140 continue;
10141 }
10142
10143 if (necp_socket_check_policy(policy_search_array[i],
10144 info->application_id,
10145 info->real_application_id,
10146 info->is_entitled,
10147 info->account_id,
10148 domain_substring,
10149 domain_dot_count,
10150 info->url,
10151 info->pid,
10152 info->pid_version,
10153 info->uid,
10154 info->real_uid,
10155 info->bound_interface_index,
10156 info->traffic_class,
10157 info->protocol,
10158 &info->local_addr,
10159 &info->remote_addr,
10160 required_agent_types,
10161 num_required_agent_types,
10162 info->has_client,
10163 info->client_flags,
10164 info->is_platform_binary,
10165 info->has_system_signed_result,
10166 proc,
10167 pf_tag,
10168 info->scheme_port,
10169 rt,
10170 info->is_loopback,
10171 debug,
10172 info->real_is_platform_binary,
10173 info->bound_interface_flags,
10174 info->bound_interface_eflags,
10175 info->bound_interface_xflags,
10176 info,
10177 info->is_delegated,
10178 so)) {
10179 if (!debug && necp_data_tracing_session_order) {
10180 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10181 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10182 NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
10183 }
10184 }
10185
10186 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
10187 if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
10188 necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
10189 if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
10190 *return_filter = control_unit;
10191 } else {
10192 // Preserve pre-existing connections only if all filters preserve.
10193 bool preserve_bit_off = false;
10194 if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
10195 (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
10196 preserve_bit_off = true;
10197 }
10198 *return_filter |= control_unit;
10199 if (preserve_bit_off == true) {
10200 *return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
10201 }
10202 }
10203 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10204 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);
10205 }
10206 }
10207 continue;
10208 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10209 if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
10210 return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10211 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10212 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);
10213 }
10214 }
10215 continue;
10216 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
10217 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10218 if (netagent_cursor < netagent_array_count_adjusted) {
10219 bool agent_already_present = false;
10220 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10221 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10222 // Already present. Mark the "SCOPED" flag if flags are necessary.
10223 agent_already_present = true;
10224 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
10225 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10226 netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
10227 }
10228 }
10229 }
10230
10231 if (!agent_already_present) {
10232 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10233 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10234 netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
10235 }
10236 netagent_cursor++;
10237 }
10238 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10239 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
10240 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10241 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
10242 policy_search_array[i]->result_parameter.netagent_id);
10243 }
10244 }
10245 continue;
10246 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
10247 bool agent_already_present = false;
10248 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10249 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10250 // Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10251 agent_already_present = true;
10252 netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10253 }
10254 }
10255 if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10256 // If not present, and flags are supported, add an entry with the "REMOVE" flag
10257 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10258 netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10259 netagent_cursor++;
10260 }
10261 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10262 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
10263 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10264 policy_search_array[i]->result_parameter.netagent_id);
10265 }
10266 continue;
10267 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
10268 u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
10269 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
10270 /* For transparent proxies, accumulate the control unit and continue to the next policy */
10271 if (return_flow_divert_aggregate_unit != NULL) {
10272 *return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
10273 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10274 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);
10275 }
10276 }
10277 continue;
10278 }
10279 }
10280
10281 // Matched policy is a skip. Do skip and continue.
10282 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10283 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
10284 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10285 skip_session_order = policy_search_array[i]->session_order + 1;
10286 if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
10287 *skip_policy_id = policy_search_array[i]->id;
10288 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10289 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);
10290 }
10291 }
10292 continue;
10293 }
10294
10295 // Matched an allow unentitled, which clears any drop order
10296 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
10297 info->drop_order = 0;
10298 continue;
10299 }
10300
10301 // Passed all tests, found a match
10302 matched_policy = policy_search_array[i];
10303 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
10304 break;
10305 }
10306 }
10307 }
10308
10309 if (return_netagent_array != NULL) {
10310 if (return_netagent_use_flags_array != NULL) {
10311 memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
10312 memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
10313 } else {
10314 for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
10315 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
10316 return_netagent_array[netagent_i] = netagent_ids[netagent_i];
10317 } else {
10318 return_netagent_array[netagent_i] = 0;
10319 }
10320 }
10321 }
10322 }
10323
10324 if (return_route_rule_id_array_count != NULL) {
10325 *return_route_rule_id_array_count = route_rule_id_count;
10326 }
10327 return matched_policy;
10328 }
10329
10330 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)10331 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
10332 {
10333 bool found_match = FALSE;
10334 ifaddr_t ifa;
10335 union necp_sockaddr_union address_storage;
10336 int family = AF_INET;
10337
10338 ifnet_head_lock_shared();
10339 ifnet_t interface = ifindex2ifnet[interface_index];
10340 ifnet_head_done();
10341
10342 if (inp == NULL || interface == NULL) {
10343 return FALSE;
10344 }
10345
10346 if (inp->inp_vflag & INP_IPV4) {
10347 family = AF_INET;
10348 } else if (inp->inp_vflag & INP_IPV6) {
10349 family = AF_INET6;
10350 } else {
10351 return FALSE;
10352 }
10353
10354 // Match socket address against interface addresses
10355 ifnet_lock_shared(interface);
10356 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
10357 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
10358 if (address_storage.sa.sa_family != family) {
10359 continue;
10360 }
10361
10362 if (family == AF_INET) {
10363 if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
10364 found_match = TRUE;
10365 break;
10366 }
10367 } else if (family == AF_INET6) {
10368 if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
10369 found_match = TRUE;
10370 break;
10371 }
10372 }
10373 }
10374 }
10375 ifnet_lock_done(interface);
10376
10377 return found_match;
10378 }
10379
10380 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10381 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10382 {
10383 if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10384 proc_t curr_proc = current_proc();
10385 proc_t sock_proc = NULL;
10386 struct socket *so = inp ? inp->inp_socket : NULL;
10387 pid_t socket_pid = (so == NULL) ? 0 :
10388 #if defined(XNU_TARGET_OS_OSX)
10389 so->so_rpid ? so->so_rpid :
10390 #endif
10391 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10392 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10393 sock_proc = proc_find(socket_pid);
10394 }
10395 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10396 if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10397 if (sock_proc) {
10398 proc_rele(sock_proc);
10399 }
10400 return NECP_BYPASS_TYPE_DROP;
10401 }
10402 if (sock_proc) {
10403 proc_rele(sock_proc);
10404 }
10405
10406 if (necp_pass_loopback > 0) {
10407 return NECP_BYPASS_TYPE_LOOPBACK;
10408 }
10409 } else if (necp_is_intcoproc(inp, NULL)) {
10410 return NECP_BYPASS_TYPE_INTCOPROC;
10411 }
10412
10413 return NECP_BYPASS_TYPE_NONE;
10414 }
10415
10416 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10417 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10418 {
10419 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10420 ifnet_t tunnel_interface = NULL;
10421
10422 ifnet_head_lock_shared();
10423 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10424 ifnet_head_done();
10425
10426 if (tunnel_interface != NULL) {
10427 tcp_set_tso(intotcpcb(inp), tunnel_interface);
10428 }
10429 }
10430
10431 static inline void
necp_unscope(struct inpcb * inp)10432 necp_unscope(struct inpcb *inp)
10433 {
10434 // If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10435 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10436 inp->inp_flags &= ~INP_BOUND_IF;
10437 inp->inp_boundifp = NULL;
10438 }
10439 }
10440
10441 static inline void
necp_clear_tunnel(struct inpcb * inp)10442 necp_clear_tunnel(struct inpcb *inp)
10443 {
10444 if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10445 inp->inp_flags &= ~INP_BOUND_IF;
10446 inp->inp_boundifp = NULL;
10447 }
10448 }
10449
10450 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10451 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10452 {
10453 // Verify netagents
10454 for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10455 struct necp_uuid_id_mapping *mapping = NULL;
10456 u_int32_t netagent_id = netagent_ids[netagent_cursor];
10457 if (netagent_id == 0) {
10458 continue;
10459 }
10460 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
10461 if (mapping != NULL) {
10462 u_int32_t agent_flags = 0;
10463 agent_flags = netagent_get_flags(mapping->uuid);
10464 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10465 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10466 continue;
10467 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10468 if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10469 int trigger_error = 0;
10470 trigger_error = netagent_kernel_trigger(mapping->uuid);
10471 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10472 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);
10473 }
10474 }
10475 return false;
10476 }
10477 }
10478 }
10479 }
10480 return true;
10481 }
10482
10483 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)10484 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10485 {
10486 struct socket *so = NULL;
10487 necp_kernel_policy_filter filter_control_unit = 0;
10488 struct necp_kernel_socket_policy *matched_policy = NULL;
10489 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10490 necp_kernel_policy_result service_action = 0;
10491 necp_kernel_policy_service service = { 0, 0 };
10492 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10493 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10494 proc_t __single socket_proc = NULL;
10495 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10496
10497 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10498 memset(&netagent_ids, 0, sizeof(netagent_ids));
10499
10500 struct necp_socket_info info = {};
10501
10502 u_int32_t flow_divert_aggregate_unit = 0;
10503
10504 if (inp == NULL) {
10505 return NECP_KERNEL_POLICY_ID_NONE;
10506 }
10507
10508 // Ignore invalid addresses
10509 if (override_local_addr != NULL &&
10510 !necp_address_is_valid(override_local_addr)) {
10511 override_local_addr = NULL;
10512 }
10513 if (override_remote_addr != NULL &&
10514 !necp_address_is_valid(override_remote_addr)) {
10515 override_remote_addr = NULL;
10516 }
10517
10518 so = inp->inp_socket;
10519
10520 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10521
10522 // Don't lock. Possible race condition, but we don't want the performance hit.
10523 if (necp_drop_management_order == 0 &&
10524 (necp_kernel_socket_policies_count == 0 ||
10525 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10526 if (necp_drop_all_order > 0 || drop_order > 0) {
10527 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10528 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10529 inp->inp_policyresult.policy_gencount = 0;
10530 inp->inp_policyresult.app_id = 0;
10531 inp->inp_policyresult.flowhash = 0;
10532 inp->inp_policyresult.results.filter_control_unit = 0;
10533 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10534 inp->inp_policyresult.results.route_rule_id = 0;
10535 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10536 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10537 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10538 } else {
10539 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10540 }
10541 }
10542 return NECP_KERNEL_POLICY_ID_NONE;
10543 }
10544
10545 // Check for loopback exception
10546 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10547 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10548 // Mark socket as a drop
10549 necp_unscope(inp);
10550 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10551 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10552 inp->inp_policyresult.policy_gencount = 0;
10553 inp->inp_policyresult.app_id = 0;
10554 inp->inp_policyresult.flowhash = 0;
10555 inp->inp_policyresult.results.filter_control_unit = 0;
10556 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10557 inp->inp_policyresult.results.route_rule_id = 0;
10558 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10559 return NECP_KERNEL_POLICY_ID_NONE;
10560 }
10561
10562 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10563 // Mark socket as a pass
10564 necp_unscope(inp);
10565 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10566 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10567 inp->inp_policyresult.policy_gencount = 0;
10568 inp->inp_policyresult.app_id = 0;
10569 inp->inp_policyresult.flowhash = 0;
10570 inp->inp_policyresult.results.filter_control_unit = 0;
10571 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10572 inp->inp_policyresult.results.route_rule_id = 0;
10573 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10574 return NECP_KERNEL_POLICY_ID_NONE;
10575 }
10576
10577 // Lock
10578 lck_rw_lock_shared(&necp_kernel_policy_lock);
10579 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);
10580
10581 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10582 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10583
10584 // Check info
10585 u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10586 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10587 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10588 inp->inp_policyresult.flowhash == flowhash) {
10589 // If already matched this socket on this generation of table, skip
10590
10591 if (info.soflow_entry != NULL) {
10592 soflow_free_flow(info.soflow_entry);
10593 }
10594
10595 // Unlock
10596 lck_rw_done(&necp_kernel_policy_lock);
10597
10598 if (socket_proc) {
10599 proc_rele(socket_proc);
10600 }
10601
10602 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10603 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10604 inp->inp_socket, info.bound_interface_index, info.protocol,
10605 inp->inp_policyresult.policy_id,
10606 inp->inp_policyresult.results.result,
10607 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10608 }
10609 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10610 return inp->inp_policyresult.policy_id;
10611 }
10612
10613 inp->inp_policyresult.app_id = info.application_id;
10614
10615 // Match socket to policy
10616 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10617 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10618 size_t route_rule_id_array_count = 0;
10619
10620 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10621 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)],
10622 &info,
10623 &filter_control_unit,
10624 route_rule_id_array,
10625 &route_rule_id_array_count,
10626 MAX_AGGREGATE_ROUTE_RULES,
10627 &service_action,
10628 &service,
10629 netagent_ids,
10630 NECP_MAX_NETAGENTS,
10631 NULL,
10632 0,
10633 NULL,
10634 0,
10635 effective_proc,
10636 0,
10637 &skip_policy_id,
10638 inp->inp_route.ro_rt,
10639 &drop_dest_policy_result,
10640 &drop_all_bypass,
10641 &flow_divert_aggregate_unit,
10642 so,
10643 debug);
10644
10645 // Check for loopback exception again after the policy match
10646 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10647 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10648 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10649 // Mark socket as a pass
10650 necp_unscope(inp);
10651 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10652 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10653 inp->inp_policyresult.policy_gencount = 0;
10654 inp->inp_policyresult.app_id = 0;
10655 inp->inp_policyresult.flowhash = 0;
10656 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10657 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10658 inp->inp_policyresult.results.route_rule_id = 0;
10659 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10660 if (info.soflow_entry != NULL) {
10661 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10662 info.soflow_entry->soflow_policies_gencount = 0;
10663 soflow_free_flow(info.soflow_entry);
10664 }
10665
10666 // Unlock
10667 lck_rw_done(&necp_kernel_policy_lock);
10668
10669 if (socket_proc) {
10670 proc_rele(socket_proc);
10671 }
10672
10673 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10674 return NECP_KERNEL_POLICY_ID_NONE;
10675 }
10676
10677 // Verify netagents
10678 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10679 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10680 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);
10681 }
10682
10683 // Mark socket as a drop if required agent is not active
10684 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10685 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10686 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10687 inp->inp_policyresult.flowhash = flowhash;
10688 inp->inp_policyresult.results.filter_control_unit = 0;
10689 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10690 inp->inp_policyresult.results.route_rule_id = 0;
10691 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10692 if (info.soflow_entry != NULL) {
10693 info.soflow_entry->soflow_filter_control_unit = 0;
10694 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10695 soflow_free_flow(info.soflow_entry);
10696 }
10697
10698 // Unlock
10699 lck_rw_done(&necp_kernel_policy_lock);
10700
10701 if (socket_proc) {
10702 proc_rele(socket_proc);
10703 }
10704
10705 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);
10706 return NECP_KERNEL_POLICY_ID_NONE;
10707 }
10708
10709 u_int32_t route_rule_id = 0;
10710 if (route_rule_id_array_count == 1) {
10711 route_rule_id = route_rule_id_array[0];
10712 } else if (route_rule_id_array_count > 1) {
10713 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10714 }
10715
10716 bool reset_tcp_tunnel_interface = false;
10717 bool send_local_network_denied_event = false;
10718 if (matched_policy) {
10719 // For PASS policy result, clear previous rescope / tunnel inteface
10720 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10721 (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10722 necp_unscope(inp);
10723 necp_clear_tunnel(inp);
10724 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10725 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10726 }
10727 }
10728 matched_policy_id = matched_policy->id;
10729 inp->inp_policyresult.policy_id = matched_policy->id;
10730 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10731 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10732 inp->inp_policyresult.flowhash = flowhash;
10733 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10734 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10735 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10736 inp->inp_policyresult.results.result = matched_policy->result;
10737 memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10738 if (info.soflow_entry != NULL) {
10739 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10740 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10741 }
10742
10743 if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10744 inp->inp_policyresult.app_id = info.real_application_id;
10745 }
10746
10747 if (necp_socket_is_connected(inp) &&
10748 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10749 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10750 NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10751 sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10752 } else if (necp_socket_is_connected(inp) &&
10753 matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10754 info.protocol == IPPROTO_TCP) {
10755 // Reset TCP socket interface based parameters if tunnel policy changes
10756 reset_tcp_tunnel_interface = true;
10757 }
10758
10759 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10760 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);
10761 }
10762
10763 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10764 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10765 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10766 // Trigger the event that we dropped due to a local network policy
10767 send_local_network_denied_event = true;
10768 }
10769 } else {
10770 bool drop_all = false;
10771 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10772 // Mark socket as a drop if set
10773 drop_all = true;
10774 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10775 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10776 }
10777 }
10778
10779 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10780 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);
10781 if (flow_divert_control_unit != 0) {
10782 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10783 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10784 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10785 inp->inp_policyresult.flowhash = flowhash;
10786 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10787 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10788 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10789 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10790 inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10791 if (info.soflow_entry != NULL) {
10792 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10793 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10794 }
10795 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);
10796 } else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10797 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10798 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10799 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10800 inp->inp_policyresult.flowhash = flowhash;
10801 inp->inp_policyresult.results.filter_control_unit = 0;
10802 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10803 inp->inp_policyresult.results.route_rule_id = 0;
10804 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10805 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);
10806 if (info.soflow_entry != NULL) {
10807 info.soflow_entry->soflow_filter_control_unit = 0;
10808 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10809 }
10810 } else {
10811 // Mark non-matching socket so we don't re-check it
10812 necp_unscope(inp);
10813 if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10814 necp_clear_tunnel(inp);
10815 }
10816 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10817 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);
10818 }
10819 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10820 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10821 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10822 inp->inp_policyresult.flowhash = flowhash;
10823 inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10824 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10825 inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10826 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10827 if (info.soflow_entry != NULL) {
10828 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10829 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10830 }
10831 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10832 }
10833 }
10834
10835 if (necp_check_missing_client_drop(effective_proc, &info) ||
10836 necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10837 // Mark as drop
10838 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10839 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10840 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10841 inp->inp_policyresult.flowhash = flowhash;
10842 inp->inp_policyresult.results.filter_control_unit = 0;
10843 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10844 inp->inp_policyresult.results.route_rule_id = 0;
10845 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10846 if (info.soflow_entry != NULL) {
10847 info.soflow_entry->soflow_filter_control_unit = 0;
10848 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10849 }
10850 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10851 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10852 }
10853 }
10854
10855 if (info.soflow_entry != NULL) {
10856 soflow_free_flow(info.soflow_entry);
10857 }
10858
10859 // Unlock
10860 lck_rw_done(&necp_kernel_policy_lock);
10861
10862 if (reset_tcp_tunnel_interface) {
10863 // Update MSS when not holding the policy lock to avoid recursive locking
10864 tcp_mtudisc(inp, 0);
10865
10866 // Update TSO flag based on the tunnel interface
10867 necp_socket_ip_tunnel_tso(inp);
10868 }
10869
10870 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10871 inp->inp_policyresult.network_denied_notifies++;
10872 #if defined(XNU_TARGET_OS_OSX)
10873 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10874 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10875 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10876 NETPOLICY_NETWORKTYPE_LOCAL);
10877 #else
10878 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10879 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10880 NETPOLICY_NETWORKTYPE_LOCAL);
10881 #endif
10882 }
10883
10884 if (socket_proc) {
10885 proc_rele(socket_proc);
10886 }
10887
10888 return matched_policy_id;
10889 }
10890
10891 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)10892 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)
10893 {
10894 u_int32_t bound_interface_flags = 0;
10895 u_int32_t bound_interface_eflags = 0;
10896 u_int32_t bound_interface_xflags = 0;
10897
10898 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
10899 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10900 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
10901 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
10902 "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
10903 cond_bound_interface_index, bound_interface_index);
10904 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10905 if (bound_interface_index == cond_bound_interface_index) {
10906 // No match, matches forbidden interface
10907 return FALSE;
10908 }
10909 } else {
10910 if (bound_interface_index != cond_bound_interface_index) {
10911 // No match, does not match required interface
10912 return FALSE;
10913 }
10914 }
10915 }
10916 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10917 if (bound_interface_index != IFSCOPE_NONE) {
10918 ifnet_head_lock_shared();
10919 ifnet_t interface = ifindex2ifnet[bound_interface_index];
10920 if (interface != NULL) {
10921 bound_interface_flags = interface->if_flags;
10922 bound_interface_eflags = interface->if_eflags;
10923 bound_interface_xflags = interface->if_xflags;
10924 }
10925 ifnet_head_done();
10926 }
10927
10928 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10929 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
10930 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10931 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
10932 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10933 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
10934 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10935 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10936 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10937 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10938 // No match, matches some forbidden interface flags
10939 return FALSE;
10940 }
10941 } else {
10942 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10943 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10944 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10945 // No match, does not match some required interface xflags
10946 return FALSE;
10947 }
10948 }
10949 }
10950 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
10951 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
10952 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
10953 if (bound_interface_index != 0) {
10954 // No match, requires a non-bound packet
10955 return FALSE;
10956 }
10957 }
10958 }
10959
10960 if (kernel_policy->condition_mask == 0) {
10961 return TRUE;
10962 }
10963
10964 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10965 necp_kernel_policy_id matched_policy_id =
10966 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10967 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
10968 "NECP_KERNEL_CONDITION_POLICY_ID",
10969 kernel_policy->cond_policy_id, 0, 0,
10970 matched_policy_id, socket_policy_id, socket_skip_policy_id);
10971 if (matched_policy_id != kernel_policy->cond_policy_id) {
10972 // No match, does not match required id
10973 return FALSE;
10974 }
10975 }
10976
10977 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10978 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
10979 "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10980 kernel_policy->cond_last_interface_index, last_interface_index);
10981 if (last_interface_index != kernel_policy->cond_last_interface_index) {
10982 return FALSE;
10983 }
10984 }
10985
10986 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10987 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
10988 "NECP_KERNEL_CONDITION_PROTOCOL",
10989 kernel_policy->cond_protocol, protocol);
10990 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10991 if (protocol == kernel_policy->cond_protocol) {
10992 // No match, matches forbidden protocol
10993 return FALSE;
10994 }
10995 } else {
10996 if (protocol != kernel_policy->cond_protocol) {
10997 // No match, does not match required protocol
10998 return FALSE;
10999 }
11000 }
11001 }
11002
11003 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11004 bool is_local = FALSE;
11005 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
11006
11007 if (rt != NULL) {
11008 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
11009 } else {
11010 is_local = necp_is_route_local(remote, include_local_addresses);
11011 }
11012 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);
11013 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11014 if (is_local) {
11015 // Match local-networks, fail
11016 return FALSE;
11017 }
11018 } else {
11019 if (!is_local) {
11020 // Either no route to validate or no match for local networks
11021 return FALSE;
11022 }
11023 }
11024 }
11025
11026 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
11027 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11028 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
11029 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
11030 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11031 if (inRange) {
11032 return FALSE;
11033 }
11034 } else {
11035 if (!inRange) {
11036 return FALSE;
11037 }
11038 }
11039 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11040 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
11041 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
11042 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11043 if (inSubnet) {
11044 return FALSE;
11045 }
11046 } else {
11047 if (!inSubnet) {
11048 return FALSE;
11049 }
11050 }
11051 }
11052 }
11053
11054 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
11055 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11056 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
11057 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
11058 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11059 if (inRange) {
11060 return FALSE;
11061 }
11062 } else {
11063 if (!inRange) {
11064 return FALSE;
11065 }
11066 }
11067 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11068 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
11069 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
11070 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11071 if (inSubnet) {
11072 return FALSE;
11073 }
11074 } else {
11075 if (!inSubnet) {
11076 return FALSE;
11077 }
11078 }
11079 }
11080 }
11081
11082 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11083 u_int16_t remote_port = 0;
11084 if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
11085 remote_port = SIN(remote)->sin_port;
11086 }
11087 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
11088 "NECP_KERNEL_CONDITION_SCHEME_PORT",
11089 0, remote_port);
11090 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11091 if (kernel_policy->cond_scheme_port == remote_port) {
11092 return FALSE;
11093 }
11094 } else {
11095 if (kernel_policy->cond_scheme_port != remote_port) {
11096 return FALSE;
11097 }
11098 }
11099 }
11100
11101 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11102 bool tags_matched = false;
11103 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
11104 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
11105 kernel_policy->cond_packet_filter_tags, pf_tag);
11106 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
11107 if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
11108 tags_matched = true;
11109 }
11110
11111 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11112 if (tags_matched) {
11113 return FALSE;
11114 }
11115 } else {
11116 if (!tags_matched) {
11117 return FALSE;
11118 }
11119 }
11120 }
11121 }
11122
11123 return TRUE;
11124 }
11125
11126 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)11127 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)
11128 {
11129 u_int32_t skip_order = 0;
11130 u_int32_t skip_session_order = 0;
11131 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11132 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)];
11133 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11134 size_t route_rule_id_count = 0;
11135 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11136 if (return_drop_all_bypass != NULL) {
11137 *return_drop_all_bypass = drop_all_bypass;
11138 }
11139
11140 if (return_route_rule_id != NULL) {
11141 *return_route_rule_id = 0;
11142 }
11143
11144 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11145
11146 if (policy_search_array != NULL) {
11147 for (int i = 0; policy_search_array[i] != NULL; i++) {
11148 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
11149 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
11150 // We've hit a drop all rule
11151 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11152 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11153 if (return_drop_all_bypass != NULL) {
11154 *return_drop_all_bypass = drop_all_bypass;
11155 }
11156 }
11157 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11158 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
11159 break;
11160 }
11161 }
11162 if (necp_drop_dest_policy.entry_count > 0 &&
11163 necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
11164 // We've hit a drop by destination address rule
11165 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
11166 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
11167 break;
11168 }
11169 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
11170 // Done skipping
11171 skip_order = 0;
11172 skip_session_order = 0;
11173 }
11174 if (skip_order) {
11175 if (policy_search_array[i]->order < skip_order) {
11176 // Skip this policy
11177 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
11178 continue;
11179 } else {
11180 // Done skipping
11181 skip_order = 0;
11182 skip_session_order = 0;
11183 }
11184 } else if (skip_session_order) {
11185 // Skip this policy
11186 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
11187 continue;
11188 }
11189
11190 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)) {
11191 if (!debug && necp_data_tracing_session_order) {
11192 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
11193 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
11194 NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
11195 }
11196 }
11197
11198 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
11199 if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
11200 route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
11201 }
11202 continue;
11203 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
11204 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
11205 skip_session_order = policy_search_array[i]->session_order + 1;
11206 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
11207 continue;
11208 }
11209
11210 // Passed all tests, found a match
11211 matched_policy = policy_search_array[i];
11212 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
11213 break;
11214 }
11215 }
11216 }
11217
11218 if (route_rule_id_count == 1) {
11219 *return_route_rule_id = route_rule_id_array[0];
11220 } else if (route_rule_id_count > 1) {
11221 *return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11222 }
11223
11224 return matched_policy;
11225 }
11226
11227 static inline bool
necp_output_bypass(struct mbuf * packet)11228 necp_output_bypass(struct mbuf *packet)
11229 {
11230 if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
11231 return true;
11232 }
11233 if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
11234 return true;
11235 }
11236 if (necp_is_intcoproc(NULL, packet)) {
11237 return true;
11238 }
11239 return false;
11240 }
11241
11242 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)11243 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
11244 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11245 {
11246 struct ip *ip = NULL;
11247 int hlen = sizeof(struct ip);
11248 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11249 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11250 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11251 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11252 u_int16_t protocol = 0;
11253 u_int32_t bound_interface_index = 0;
11254 u_int32_t last_interface_index = 0;
11255 union necp_sockaddr_union local_addr = { };
11256 union necp_sockaddr_union remote_addr = { };
11257 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11258 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11259 u_int16_t pf_tag = 0;
11260
11261 if (result) {
11262 *result = 0;
11263 }
11264
11265 if (result_parameter) {
11266 memset(result_parameter, 0, sizeof(*result_parameter));
11267 }
11268
11269 if (packet == NULL) {
11270 return NECP_KERNEL_POLICY_ID_NONE;
11271 }
11272
11273 socket_policy_id = necp_get_policy_id_from_packet(packet);
11274 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11275 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11276
11277 // Exit early for an empty list
11278 // Don't lock. Possible race condition, but we don't want the performance hit.
11279 if (necp_kernel_ip_output_policies_count == 0 ||
11280 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
11281 if (necp_drop_all_order > 0) {
11282 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11283 if (result) {
11284 if (necp_output_bypass(packet)) {
11285 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11286 } else {
11287 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11288 }
11289 }
11290 }
11291
11292 return matched_policy_id;
11293 }
11294
11295 // Check for loopback exception
11296 if (necp_output_bypass(packet)) {
11297 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11298 if (result) {
11299 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11300 }
11301 return matched_policy_id;
11302 }
11303
11304 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11305
11306 // Process packet to get relevant fields
11307 ip = mtod(packet, struct ip *);
11308 #ifdef _IP_VHL
11309 hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
11310 #else
11311 hlen = ip->ip_hl << 2;
11312 #endif
11313
11314 protocol = ip->ip_p;
11315
11316 if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
11317 (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
11318 ipoa->ipoa_boundif != IFSCOPE_NONE) {
11319 bound_interface_index = ipoa->ipoa_boundif;
11320 }
11321
11322 local_addr.sin.sin_family = AF_INET;
11323 local_addr.sin.sin_len = sizeof(struct sockaddr_in);
11324 memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
11325
11326 remote_addr.sin.sin_family = AF_INET;
11327 remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
11328 memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
11329
11330 switch (protocol) {
11331 case IPPROTO_TCP: {
11332 struct tcphdr th;
11333 if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
11334 m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
11335 SIN(&local_addr)->sin_port = th.th_sport;
11336 SIN(&remote_addr)->sin_port = th.th_dport;
11337 }
11338 break;
11339 }
11340 case IPPROTO_UDP: {
11341 struct udphdr uh;
11342 if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
11343 m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
11344 SIN(&local_addr)->sin_port = uh.uh_sport;
11345 SIN(&remote_addr)->sin_port = uh.uh_dport;
11346 }
11347 break;
11348 }
11349 default: {
11350 SIN(&local_addr)->sin_port = 0;
11351 SIN(&remote_addr)->sin_port = 0;
11352 break;
11353 }
11354 }
11355
11356 // Match packet to policy
11357 lck_rw_lock_shared(&necp_kernel_policy_lock);
11358 u_int32_t route_rule_id = 0;
11359
11360 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11361 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
11362
11363 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);
11364 if (matched_policy) {
11365 matched_policy_id = matched_policy->id;
11366 if (result) {
11367 *result = matched_policy->result;
11368 }
11369
11370 if (result_parameter) {
11371 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11372 }
11373
11374 if (route_rule_id != 0 &&
11375 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11376 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11377 }
11378
11379 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11380 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);
11381 }
11382 } else {
11383 bool drop_all = false;
11384 /*
11385 * Apply drop-all only to packets which have never matched a primary policy (check
11386 * if the packet saved policy id is none or falls within the socket policy id range).
11387 */
11388 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11389 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11390 drop_all = true;
11391 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11392 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11393 }
11394 }
11395 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11396 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11397 if (result) {
11398 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11399 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
11400 }
11401 } else if (route_rule_id != 0 &&
11402 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11403 // If we matched a route rule, mark it
11404 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11405 }
11406 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11407 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);
11408 }
11409 }
11410
11411 lck_rw_done(&necp_kernel_policy_lock);
11412
11413 return matched_policy_id;
11414 }
11415
11416 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)11417 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11418 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11419 {
11420 struct ip6_hdr *ip6 = NULL;
11421 int next = -1;
11422 int offset = 0;
11423 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11424 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11425 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11426 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11427 u_int16_t protocol = 0;
11428 u_int32_t bound_interface_index = 0;
11429 u_int32_t last_interface_index = 0;
11430 union necp_sockaddr_union local_addr = { };
11431 union necp_sockaddr_union remote_addr = { };
11432 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11433 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11434 u_int16_t pf_tag = 0;
11435
11436 if (result) {
11437 *result = 0;
11438 }
11439
11440 if (result_parameter) {
11441 memset(result_parameter, 0, sizeof(*result_parameter));
11442 }
11443
11444 if (packet == NULL) {
11445 return NECP_KERNEL_POLICY_ID_NONE;
11446 }
11447
11448 socket_policy_id = necp_get_policy_id_from_packet(packet);
11449 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11450 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11451
11452 // Exit early for an empty list
11453 // Don't lock. Possible race condition, but we don't want the performance hit.
11454 if (necp_drop_management_order == 0 &&
11455 (necp_kernel_ip_output_policies_count == 0 ||
11456 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11457 if (necp_drop_all_order > 0) {
11458 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11459 if (result) {
11460 if (necp_output_bypass(packet)) {
11461 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11462 } else {
11463 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11464 }
11465 }
11466 }
11467
11468 return matched_policy_id;
11469 }
11470
11471 // Check for loopback exception
11472 if (necp_output_bypass(packet)) {
11473 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11474 if (result) {
11475 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11476 }
11477 return matched_policy_id;
11478 }
11479
11480 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11481
11482 // Process packet to get relevant fields
11483 ip6 = mtod(packet, struct ip6_hdr *);
11484
11485 if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11486 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11487 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11488 bound_interface_index = ip6oa->ip6oa_boundif;
11489 }
11490
11491 SIN6(&local_addr)->sin6_family = AF_INET6;
11492 SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11493 memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11494
11495 SIN6(&remote_addr)->sin6_family = AF_INET6;
11496 SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11497 memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11498
11499 offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11500 if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11501 protocol = next;
11502 switch (protocol) {
11503 case IPPROTO_TCP: {
11504 struct tcphdr th;
11505 if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11506 m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11507 SIN6(&local_addr)->sin6_port = th.th_sport;
11508 SIN6(&remote_addr)->sin6_port = th.th_dport;
11509 }
11510 break;
11511 }
11512 case IPPROTO_UDP: {
11513 struct udphdr uh;
11514 if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11515 m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11516 SIN6(&local_addr)->sin6_port = uh.uh_sport;
11517 SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11518 }
11519 break;
11520 }
11521 default: {
11522 SIN6(&local_addr)->sin6_port = 0;
11523 SIN6(&remote_addr)->sin6_port = 0;
11524 break;
11525 }
11526 }
11527 }
11528
11529 // Match packet to policy
11530 lck_rw_lock_shared(&necp_kernel_policy_lock);
11531 u_int32_t route_rule_id = 0;
11532
11533 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11534 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11535
11536 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);
11537 if (matched_policy) {
11538 matched_policy_id = matched_policy->id;
11539 if (result) {
11540 *result = matched_policy->result;
11541 }
11542
11543 if (result_parameter) {
11544 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11545 }
11546
11547 if (route_rule_id != 0 &&
11548 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11549 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11550 }
11551
11552 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11553 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);
11554 }
11555 } else {
11556 bool drop_all = false;
11557 /*
11558 * Apply drop-all only to packets which have never matched a primary policy (check
11559 * if the packet saved policy id is none or falls within the socket policy id range).
11560 */
11561 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11562 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11563 drop_all = true;
11564 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11565 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11566 }
11567 }
11568 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11569 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11570 if (result) {
11571 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11572 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11573 }
11574 } else if (route_rule_id != 0 &&
11575 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11576 // If we matched a route rule, mark it
11577 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11578 }
11579 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11580 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);
11581 }
11582 }
11583
11584 lck_rw_done(&necp_kernel_policy_lock);
11585
11586 return matched_policy_id;
11587 }
11588
11589 // Utilities
11590 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11591 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11592 {
11593 int cmp = 0;
11594
11595 if (addr == NULL || range_start == NULL || range_end == NULL) {
11596 return FALSE;
11597 }
11598
11599 /* Must be greater than or equal to start */
11600 cmp = necp_addr_compare(addr, range_start, 1);
11601 if (cmp != 0 && cmp != 1) {
11602 return FALSE;
11603 }
11604
11605 /* Must be less than or equal to end */
11606 cmp = necp_addr_compare(addr, range_end, 1);
11607 if (cmp != 0 && cmp != -1) {
11608 return FALSE;
11609 }
11610
11611 return TRUE;
11612 }
11613
11614 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)11615 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11616 {
11617 int cmp = 0;
11618
11619 if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11620 return FALSE;
11621 }
11622
11623 /* Must be greater than or equal to start */
11624 cmp = necp_addr_compare(inner_range_start, range_start, 1);
11625 if (cmp != 0 && cmp != 1) {
11626 return FALSE;
11627 }
11628
11629 /* Must be less than or equal to end */
11630 cmp = necp_addr_compare(inner_range_end, range_end, 1);
11631 if (cmp != 0 && cmp != -1) {
11632 return FALSE;
11633 }
11634
11635 return TRUE;
11636 }
11637
11638 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11639 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11640 {
11641 if (addr == NULL || subnet_addr == NULL) {
11642 return FALSE;
11643 }
11644
11645 if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11646 return FALSE;
11647 }
11648
11649 switch (addr->sa_family) {
11650 case AF_INET: {
11651 if (satosin(subnet_addr)->sin_port != 0 &&
11652 satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11653 return FALSE;
11654 }
11655 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11656 }
11657 case AF_INET6: {
11658 if (satosin6(subnet_addr)->sin6_port != 0 &&
11659 satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11660 return FALSE;
11661 }
11662 if (satosin6(addr)->sin6_scope_id &&
11663 satosin6(subnet_addr)->sin6_scope_id &&
11664 satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11665 return FALSE;
11666 }
11667 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11668 }
11669 default: {
11670 return FALSE;
11671 }
11672 }
11673
11674 return FALSE;
11675 }
11676
11677 /*
11678 * Return values:
11679 * -1: sa1 < sa2
11680 * 0: sa1 == sa2
11681 * 1: sa1 > sa2
11682 * 2: Not comparable or error
11683 */
11684 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11685 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11686 {
11687 int result = 0;
11688 int port_result = 0;
11689
11690 if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11691 return 2;
11692 }
11693
11694 if (sa1->sa_len == 0) {
11695 return 0;
11696 }
11697
11698 switch (sa1->sa_family) {
11699 case AF_INET: {
11700 if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11701 return 2;
11702 }
11703
11704 result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11705
11706 if (check_port) {
11707 if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11708 port_result = -1;
11709 } else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11710 port_result = 1;
11711 }
11712
11713 if (result == 0) {
11714 result = port_result;
11715 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11716 return 2;
11717 }
11718 }
11719
11720 break;
11721 }
11722 case AF_INET6: {
11723 if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11724 return 2;
11725 }
11726
11727 if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11728 return 2;
11729 }
11730
11731 result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11732
11733 if (check_port) {
11734 if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11735 port_result = -1;
11736 } else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11737 port_result = 1;
11738 }
11739
11740 if (result == 0) {
11741 result = port_result;
11742 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11743 return 2;
11744 }
11745 }
11746
11747 break;
11748 }
11749 default: {
11750 result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11751 break;
11752 }
11753 }
11754
11755 if (result < 0) {
11756 result = (-1);
11757 } else if (result > 0) {
11758 result = (1);
11759 }
11760
11761 return result;
11762 }
11763
11764 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11765 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11766 {
11767 u_int8_t mask;
11768
11769 /* Handle null pointers */
11770 if (p1 == NULL || p2 == NULL) {
11771 return p1 == p2;
11772 }
11773
11774 while (bits >= 8) {
11775 if (*p1++ != *p2++) {
11776 return FALSE;
11777 }
11778 bits -= 8;
11779 }
11780
11781 if (bits > 0) {
11782 mask = ~((1 << (8 - bits)) - 1);
11783 if ((*p1 & mask) != (*p2 & mask)) {
11784 return FALSE;
11785 }
11786 }
11787 return TRUE;
11788 }
11789
11790 static bool
necp_addr_is_empty(struct sockaddr * addr)11791 necp_addr_is_empty(struct sockaddr *addr)
11792 {
11793 if (addr == NULL) {
11794 return TRUE;
11795 }
11796
11797 if (addr->sa_len == 0) {
11798 return TRUE;
11799 }
11800
11801 switch (addr->sa_family) {
11802 case AF_INET: {
11803 static struct sockaddr_in ipv4_empty_address = {
11804 .sin_len = sizeof(struct sockaddr_in),
11805 .sin_family = AF_INET,
11806 .sin_port = 0,
11807 .sin_addr = { .s_addr = 0 }, // 0.0.0.0
11808 .sin_zero = {0},
11809 };
11810 if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11811 return TRUE;
11812 } else {
11813 return FALSE;
11814 }
11815 }
11816 case AF_INET6: {
11817 static struct sockaddr_in6 ipv6_empty_address = {
11818 .sin6_len = sizeof(struct sockaddr_in6),
11819 .sin6_family = AF_INET6,
11820 .sin6_port = 0,
11821 .sin6_flowinfo = 0,
11822 .sin6_addr = IN6ADDR_ANY_INIT, // ::
11823 .sin6_scope_id = 0,
11824 };
11825 if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11826 return TRUE;
11827 } else {
11828 return FALSE;
11829 }
11830 }
11831 default:
11832 return FALSE;
11833 }
11834
11835 return FALSE;
11836 }
11837
11838 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)11839 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)
11840 {
11841 bool qos_marking = FALSE;
11842 int exception_index = 0;
11843 struct necp_route_rule *route_rule = NULL;
11844
11845 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11846 if (route_rule == NULL) {
11847 qos_marking = FALSE;
11848 goto done;
11849 }
11850
11851 if (route_rule->match_netagent_id != 0) {
11852 if (netagent_array == NULL || netagent_array_count == 0) {
11853 // No agents, ignore rule
11854 goto done;
11855 }
11856 bool found_match = FALSE;
11857 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11858 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11859 found_match = TRUE;
11860 break;
11861 }
11862 }
11863 if (!found_match) {
11864 // Agents don't match, ignore rule
11865 goto done;
11866 }
11867 }
11868
11869 qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11870
11871 if (ifp == NULL) {
11872 goto done;
11873 }
11874
11875 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11876 if (route_rule->exception_if_indices[exception_index] == 0) {
11877 break;
11878 }
11879 if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
11880 continue;
11881 }
11882 if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
11883 qos_marking = TRUE;
11884 if (necp_debug > 2) {
11885 NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
11886 route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
11887 }
11888 goto done;
11889 }
11890 }
11891
11892 if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
11893 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
11894 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
11895 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
11896 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
11897 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
11898 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
11899 qos_marking = TRUE;
11900 if (necp_debug > 2) {
11901 NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d for Rule %d Allowed %d",
11902 route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
11903 route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action, route_rule_id, qos_marking);
11904 }
11905 goto done;
11906 }
11907 done:
11908 if (necp_debug > 1) {
11909 NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
11910 route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
11911 }
11912 return qos_marking;
11913 }
11914
11915 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)11916 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)
11917 {
11918 bool new_qos_marking = old_qos_marking;
11919 struct ifnet *ifp = interface;
11920
11921 if (net_qos_policy_restricted == 0) {
11922 return new_qos_marking;
11923 }
11924
11925 /*
11926 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
11927 */
11928 if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
11929 return new_qos_marking;
11930 }
11931
11932 lck_rw_lock_shared(&necp_kernel_policy_lock);
11933
11934 if (ifp == NULL && route != NULL) {
11935 ifp = route->rt_ifp;
11936 }
11937 /*
11938 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
11939 */
11940 if (ifp == NULL || route_rule_id == 0) {
11941 new_qos_marking = FALSE;
11942 goto done;
11943 }
11944
11945 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11946 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11947 if (aggregate_route_rule != NULL) {
11948 int index = 0;
11949 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11950 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11951 if (sub_route_rule_id == 0) {
11952 break;
11953 }
11954 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
11955 if (new_qos_marking == TRUE) {
11956 break;
11957 }
11958 }
11959 }
11960 } else {
11961 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
11962 }
11963 /*
11964 * Now that we have an interface we remember the gencount
11965 */
11966 *qos_marking_gencount = necp_kernel_socket_policies_gencount;
11967
11968 done:
11969 lck_rw_done(&necp_kernel_policy_lock);
11970 return new_qos_marking;
11971 }
11972
11973 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)11974 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11975 {
11976 bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11977
11978 if (net_qos_policy_restricted == 0) {
11979 return;
11980 }
11981 if (inp->inp_socket == NULL) {
11982 return;
11983 }
11984 if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11985 return;
11986 }
11987
11988 qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
11989
11990 if (qos_marking == TRUE) {
11991 inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
11992 } else {
11993 inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
11994 }
11995 }
11996
11997 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)11998 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
11999 {
12000 if (ifp != NULL &&
12001 (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12002 ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12003 return true;
12004 }
12005 if (delegated_ifp != NULL &&
12006 (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12007 delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12008 return true;
12009 }
12010 return false;
12011 }
12012
12013 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)12014 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,
12015 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12016 {
12017 bool default_is_allowed = TRUE;
12018 u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
12019 int exception_index = 0;
12020 struct ifnet *delegated_ifp = NULL;
12021 struct necp_route_rule *route_rule = NULL;
12022
12023 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12024 if (route_rule == NULL) {
12025 return TRUE;
12026 }
12027
12028 if (route_rule->match_netagent_id != 0) {
12029 if (netagent_array == NULL || netagent_array_count == 0) {
12030 // No agents, ignore rule
12031 return TRUE;
12032 }
12033 bool found_match = FALSE;
12034 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12035 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12036 found_match = TRUE;
12037 break;
12038 }
12039 }
12040 if (!found_match) {
12041 // Agents don't match, ignore rule
12042 return TRUE;
12043 }
12044 }
12045
12046 default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
12047 if (ifp == NULL && route != NULL) {
12048 ifp = route->rt_ifp;
12049 }
12050 if (ifp == NULL) {
12051 if (necp_debug > 1 && !default_is_allowed) {
12052 NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12053 }
12054 return default_is_allowed;
12055 }
12056
12057 delegated_ifp = ifp->if_delegated.ifp;
12058 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12059 if (route_rule->exception_if_indices[exception_index] == 0) {
12060 break;
12061 }
12062 if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
12063 (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
12064 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12065 const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
12066 if (necp_debug > 1 && lqm_abort) {
12067 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
12068 route_rule->exception_if_indices[exception_index], route_rule_id);
12069 }
12070 return false;
12071 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
12072 if (necp_debug > 1) {
12073 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));
12074 }
12075 if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
12076 *interface_type_denied = route_rule->effective_type;
12077 }
12078 return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
12079 }
12080 }
12081 }
12082
12083 if (IFNET_IS_CELLULAR(ifp)) {
12084 if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12085 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12086 if (interface_type_denied != NULL) {
12087 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12088 if (route_rule->effective_type != 0) {
12089 *interface_type_denied = route_rule->effective_type;
12090 }
12091 }
12092 // Mark aggregate action as deny
12093 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12094 }
12095 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
12096 if (interface_type_denied != NULL) {
12097 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12098 if (route_rule->effective_type != 0) {
12099 *interface_type_denied = route_rule->effective_type;
12100 }
12101 }
12102 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12103 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12104 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
12105 // Deny wins if there is a conflict
12106 type_aggregate_action = route_rule->cellular_action;
12107 }
12108 }
12109 }
12110
12111 if (IFNET_IS_WIFI(ifp)) {
12112 if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12113 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12114 if (interface_type_denied != NULL) {
12115 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12116 if (route_rule->effective_type != 0) {
12117 *interface_type_denied = route_rule->effective_type;
12118 }
12119 }
12120 // Mark aggregate action as deny
12121 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12122 }
12123 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
12124 if (interface_type_denied != NULL) {
12125 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12126 if (route_rule->effective_type != 0) {
12127 *interface_type_denied = route_rule->effective_type;
12128 }
12129 }
12130 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12131 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12132 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
12133 // Deny wins if there is a conflict
12134 type_aggregate_action = route_rule->wifi_action;
12135 }
12136 }
12137 }
12138
12139 if (IFNET_IS_COMPANION_LINK(ifp) ||
12140 (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
12141 if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12142 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12143 if (interface_type_denied != NULL) {
12144 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12145 if (route_rule->effective_type != 0) {
12146 *interface_type_denied = route_rule->effective_type;
12147 }
12148 }
12149 // Mark aggregate action as deny
12150 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12151 }
12152 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
12153 if (interface_type_denied != NULL) {
12154 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12155 if (route_rule->effective_type != 0) {
12156 *interface_type_denied = route_rule->effective_type;
12157 }
12158 }
12159 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12160 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12161 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
12162 // Deny wins if there is a conflict
12163 type_aggregate_action = route_rule->companion_action;
12164 }
12165 }
12166 }
12167
12168 if (IFNET_IS_WIRED(ifp)) {
12169 if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12170 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12171 if (interface_type_denied != NULL) {
12172 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12173 if (route_rule->effective_type != 0) {
12174 *interface_type_denied = route_rule->effective_type;
12175 }
12176 }
12177 // Mark aggregate action as deny
12178 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12179 }
12180 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
12181 if (interface_type_denied != NULL) {
12182 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12183 if (route_rule->effective_type != 0) {
12184 *interface_type_denied = route_rule->effective_type;
12185 }
12186 }
12187 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12188 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12189 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
12190 // Deny wins if there is a conflict
12191 type_aggregate_action = route_rule->wired_action;
12192 }
12193 }
12194 }
12195
12196 if (IFNET_IS_EXPENSIVE(ifp)) {
12197 if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12198 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12199 // Mark aggregate action as deny
12200 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12201 }
12202 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
12203 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12204 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12205 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
12206 // Deny wins if there is a conflict
12207 type_aggregate_action = route_rule->expensive_action;
12208 }
12209 }
12210 }
12211
12212 if (IFNET_IS_CONSTRAINED(ifp)) {
12213 if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12214 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12215 // Mark aggregate action as deny
12216 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12217 }
12218 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
12219 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12220 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12221 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
12222 // Deny wins if there is a conflict
12223 type_aggregate_action = route_rule->constrained_action;
12224 }
12225 }
12226 }
12227
12228 if (IFNET_IS_VPN(ifp)) {
12229 if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12230 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12231 // Mark aggregate action as deny
12232 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12233 }
12234 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
12235 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12236 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12237 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
12238 // Deny wins if there is a conflict
12239 type_aggregate_action = route_rule->vpn_action;
12240 }
12241 }
12242 }
12243
12244 if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
12245 if (necp_debug > 1) {
12246 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));
12247 }
12248 return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
12249 }
12250
12251 if (necp_debug > 1 && !default_is_allowed) {
12252 NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12253 }
12254 return default_is_allowed;
12255 }
12256
12257 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)12258 necp_proc_is_allowed_on_management_interface(proc_t proc)
12259 {
12260 bool allowed = false;
12261 const task_t __single task = proc_task(proc);
12262
12263 if (task != NULL) {
12264 if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
12265 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
12266 #if DEBUG || DEVELOPMENT
12267 || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
12268 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
12269 #endif /* DEBUG || DEVELOPMENT */
12270 ) {
12271 allowed = true;
12272 }
12273 }
12274 return allowed;
12275 }
12276
12277 __attribute__((noinline))
12278 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)12279 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12280 {
12281 char buf[128];
12282
12283 if (inp != NULL) {
12284 inp_snprintf_tuple(inp, buf, sizeof(buf));
12285 } else {
12286 *buf = 0;
12287 }
12288 os_log(OS_LOG_DEFAULT,
12289 "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
12290 proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
12291 proc != NULL ? proc_getpid(proc) : proc_selfpid(),
12292 inp != NULL ? buf : "",
12293 ifp->if_xname);
12294 }
12295
12296 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)12297 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12298 {
12299 if (if_management_interface_check_needed == false) {
12300 return true;
12301 }
12302 if (necp_drop_management_order == 0) {
12303 return true;
12304 }
12305 if (ifp == NULL && route != NULL) {
12306 ifp = route->rt_ifp;
12307 }
12308 if (ifp == NULL) {
12309 return true;
12310 }
12311
12312 if (IFNET_IS_MANAGEMENT(ifp)) {
12313 bool allowed = true;
12314
12315 if (inp != NULL) {
12316 /*
12317 * The entitlement check is already performed for socket flows
12318 */
12319 allowed = INP_MANAGEMENT_ALLOWED(inp);
12320 } else if (proc != NULL) {
12321 allowed = necp_proc_is_allowed_on_management_interface(proc);
12322 }
12323 if (__improbable(if_management_verbose > 1 && allowed == false)) {
12324 necp_log_interface_not_allowed(ifp, proc, inp);
12325 }
12326 return allowed;
12327 }
12328 return true;
12329 }
12330
12331 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)12332 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,
12333 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12334 {
12335 if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
12336 if (necp_debug > 1) {
12337 NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
12338 }
12339 return TRUE;
12340 }
12341
12342 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12343 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12344 if (aggregate_route_rule != NULL) {
12345 int index = 0;
12346 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12347 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12348 if (sub_route_rule_id == 0) {
12349 break;
12350 }
12351 if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
12352 return FALSE;
12353 }
12354 }
12355 }
12356 } else {
12357 return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
12358 }
12359
12360 return TRUE;
12361 }
12362
12363 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)12364 necp_route_rule_matches_agents(u_int32_t route_rule_id)
12365 {
12366 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12367 if (route_rule == NULL) {
12368 return false;
12369 }
12370
12371 return route_rule->match_netagent_id != 0;
12372 }
12373
12374 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)12375 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)
12376 {
12377 if (remove == NULL) {
12378 return 0;
12379 }
12380
12381 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12382 if (route_rule == NULL) {
12383 return 0;
12384 }
12385
12386 // No netagent, skip
12387 if (route_rule->netagent_id == 0) {
12388 return 0;
12389 }
12390
12391 if (route_rule->match_netagent_id != 0) {
12392 if (netagent_array == NULL || netagent_array_count == 0) {
12393 // No agents, ignore rule
12394 return 0;
12395 }
12396 bool found_match = FALSE;
12397 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12398 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12399 found_match = TRUE;
12400 break;
12401 }
12402 }
12403 if (!found_match) {
12404 // Agents don't match, ignore rule
12405 return 0;
12406 }
12407 }
12408
12409 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12410 if (ifp == NULL) {
12411 // No interface, apply the default action
12412 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12413 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12414 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12415 return route_rule->netagent_id;
12416 }
12417 return 0;
12418 }
12419
12420 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12421 if (route_rule->exception_if_indices[exception_index] == 0) {
12422 break;
12423 }
12424 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12425 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12426 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12427 route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12428 *remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12429 return route_rule->netagent_id;
12430 }
12431 return 0;
12432 }
12433 }
12434
12435 if (ifp->if_type == IFT_CELLULAR &&
12436 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12437 if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12438 route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12439 *remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12440 return route_rule->netagent_id;
12441 }
12442 return 0;
12443 }
12444
12445 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12446 route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12447 if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12448 route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12449 *remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12450 return route_rule->netagent_id;
12451 }
12452 return 0;
12453 }
12454
12455 if (IFNET_IS_COMPANION_LINK(ifp) &&
12456 route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12457 if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12458 route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12459 *remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12460 return route_rule->netagent_id;
12461 }
12462 return 0;
12463 }
12464
12465 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12466 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12467 if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12468 route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12469 *remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12470 return route_rule->netagent_id;
12471 }
12472 return 0;
12473 }
12474
12475 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12476 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12477 if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12478 route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12479 *remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12480 return route_rule->netagent_id;
12481 }
12482 return 0;
12483 }
12484
12485 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12486 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12487 if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12488 route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12489 *remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12490 return route_rule->netagent_id;
12491 }
12492 return 0;
12493 }
12494
12495 if (ifp->if_xflags & IFXF_IS_VPN &&
12496 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12497 if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12498 route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12499 *remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12500 return route_rule->netagent_id;
12501 }
12502 return 0;
12503 }
12504
12505 // No more specific case matched, apply the default action
12506 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12507 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12508 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12509 return route_rule->netagent_id;
12510 }
12511
12512 return 0;
12513 }
12514
12515 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)12516 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)
12517 {
12518 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12519 if (route_rule == NULL) {
12520 return 0;
12521 }
12522
12523 // No control unit, skip
12524 if (route_rule->control_unit == 0) {
12525 return 0;
12526 }
12527
12528 if (route_rule->match_netagent_id != 0) {
12529 if (netagent_array == NULL || netagent_array_count == 0) {
12530 // No agents, ignore rule
12531 return 0;
12532 }
12533 bool found_match = FALSE;
12534 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12535 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12536 found_match = TRUE;
12537 break;
12538 }
12539 }
12540 if (!found_match) {
12541 // Agents don't match, ignore rule
12542 return 0;
12543 }
12544 }
12545
12546 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12547 if (ifp == NULL) {
12548 // No interface, apply the default action
12549 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12550 return route_rule->control_unit;
12551 }
12552 return 0;
12553 }
12554
12555 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12556 if (route_rule->exception_if_indices[exception_index] == 0) {
12557 break;
12558 }
12559 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12560 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12561 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12562 return route_rule->control_unit;
12563 }
12564 return 0;
12565 }
12566 }
12567
12568 if (ifp->if_type == IFT_CELLULAR &&
12569 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12570 if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12571 return route_rule->control_unit;
12572 }
12573 return 0;
12574 }
12575
12576 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12577 route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12578 if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12579 return route_rule->control_unit;
12580 }
12581 return 0;
12582 }
12583
12584 if (IFNET_IS_COMPANION_LINK(ifp) &&
12585 route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12586 if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12587 return route_rule->control_unit;
12588 }
12589 return 0;
12590 }
12591
12592 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12593 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12594 if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12595 return route_rule->control_unit;
12596 }
12597 return 0;
12598 }
12599
12600 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12601 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12602 if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12603 return route_rule->control_unit;
12604 }
12605 return 0;
12606 }
12607
12608 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12609 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12610 if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12611 return route_rule->control_unit;
12612 }
12613 return 0;
12614 }
12615
12616 if (ifp->if_xflags & IFXF_IS_VPN &&
12617 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12618 if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12619 return route_rule->control_unit;
12620 }
12621 return 0;
12622 }
12623
12624 // No more specific case matched, apply the default action
12625 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12626 return route_rule->control_unit;
12627 }
12628 return 0;
12629 }
12630
12631 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)12632 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,
12633 u_int32_t *flow_divert_aggregate_unit)
12634 {
12635 if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12636 return 0;
12637 }
12638
12639 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12640 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12641 if (aggregate_route_rule != NULL) {
12642 int index = 0;
12643 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12644 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12645 if (sub_route_rule_id == 0) {
12646 break;
12647 }
12648 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12649 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12650 // For transparent proxies, accumulate the control unit and continue to the next route rule
12651 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12652 continue;
12653 }
12654
12655 if (control_unit != 0) {
12656 return control_unit;
12657 }
12658 }
12659 }
12660 } else {
12661 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12662 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12663 // For transparent proxies, accumulate the control unit and let the caller continue
12664 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12665 return 0;
12666 }
12667 return control_unit;
12668 }
12669
12670 return 0;
12671 }
12672
12673 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12674 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12675 {
12676 bool is_allowed = true;
12677 u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12678 if (route_rule_id != 0 &&
12679 interface != NULL) {
12680 lck_rw_lock_shared(&necp_kernel_policy_lock);
12681 is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
12682 lck_rw_done(&necp_kernel_policy_lock);
12683 }
12684 return is_allowed;
12685 }
12686
12687 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12688 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12689 {
12690 size_t netagent_cursor;
12691 for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12692 struct necp_uuid_id_mapping *mapping = NULL;
12693 u_int32_t netagent_id = netagent_ids[netagent_cursor];
12694 if (netagent_id == 0) {
12695 continue;
12696 }
12697 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
12698 if (mapping != NULL) {
12699 u_int32_t agent_flags = 0;
12700 agent_flags = netagent_get_flags(mapping->uuid);
12701 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12702 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12703 continue;
12704 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12705 return FALSE;
12706 }
12707 }
12708 }
12709 }
12710 return TRUE;
12711 }
12712
12713 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12714 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12715 {
12716 bool allowed_to_receive = TRUE;
12717
12718 if (pf_tag == PF_TAG_ID_STACK_DROP &&
12719 (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12720 allowed_to_receive = FALSE;
12721 }
12722
12723 return allowed_to_receive;
12724 }
12725
12726 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)12727 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)
12728 {
12729 u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12730 bool allowed_to_receive = TRUE;
12731 struct necp_socket_info info = {};
12732 u_int32_t flowhash = 0;
12733 necp_kernel_policy_result service_action = 0;
12734 necp_kernel_policy_service service = { 0, 0 };
12735 u_int32_t route_rule_id = 0;
12736 struct rtentry *route = NULL;
12737 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12738 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12739 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12740 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12741 proc_t __single socket_proc = NULL;
12742 necp_kernel_policy_filter filter_control_unit = 0;
12743 u_int32_t pass_flags = 0;
12744 u_int32_t flow_divert_aggregate_unit = 0;
12745 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12746 int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12747
12748 memset(&netagent_ids, 0, sizeof(netagent_ids));
12749
12750 if (return_policy_id) {
12751 *return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12752 }
12753 if (return_skip_policy_id) {
12754 *return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12755 }
12756 if (return_route_rule_id) {
12757 *return_route_rule_id = 0;
12758 }
12759 if (return_pass_flags) {
12760 *return_pass_flags = 0;
12761 }
12762
12763 if (inp == NULL) {
12764 goto done;
12765 }
12766
12767 route = inp->inp_route.ro_rt;
12768
12769 struct socket *so = inp->inp_socket;
12770
12771 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12772
12773 // Don't lock. Possible race condition, but we don't want the performance hit.
12774 if (necp_drop_management_order == 0 &&
12775 (necp_kernel_socket_policies_count == 0 ||
12776 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12777 if (necp_drop_all_order > 0 || drop_order > 0) {
12778 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12779 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12780 allowed_to_receive = TRUE;
12781 } else {
12782 allowed_to_receive = FALSE;
12783 }
12784 }
12785 goto done;
12786 }
12787
12788 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
12789 if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12790 bool policies_have_changed = FALSE;
12791 bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12792 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12793 policies_have_changed = TRUE;
12794 } else {
12795 if (inp->inp_policyresult.results.route_rule_id != 0) {
12796 lck_rw_lock_shared(&necp_kernel_policy_lock);
12797 if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
12798 route_allowed = FALSE;
12799 }
12800 lck_rw_done(&necp_kernel_policy_lock);
12801 }
12802 }
12803
12804 if (!policies_have_changed) {
12805 if (debug) {
12806 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);
12807 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12808 }
12809
12810 if (!route_allowed ||
12811 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12812 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12813 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12814 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12815 allowed_to_receive = FALSE;
12816 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);
12817 } else {
12818 if (return_policy_id) {
12819 *return_policy_id = inp->inp_policyresult.policy_id;
12820 }
12821 if (return_skip_policy_id) {
12822 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12823 }
12824 if (return_route_rule_id) {
12825 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12826 }
12827 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12828 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12829 }
12830 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);
12831 }
12832 goto done;
12833 }
12834 }
12835
12836 // Check for loopback exception
12837 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12838 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12839 allowed_to_receive = FALSE;
12840 goto done;
12841 }
12842 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
12843 allowed_to_receive = TRUE;
12844 goto done;
12845 }
12846
12847 // Actually calculate policy result
12848 lck_rw_lock_shared(&necp_kernel_policy_lock);
12849 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);
12850
12851 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12852 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
12853
12854 flowhash = necp_socket_calc_flowhash_locked(&info);
12855 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12856 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
12857 inp->inp_policyresult.flowhash == flowhash) {
12858 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12859 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12860 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12861 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
12862 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12863 (inp->inp_policyresult.results.route_rule_id != 0 &&
12864 !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
12865 allowed_to_receive = FALSE;
12866 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);
12867 } else {
12868 if (return_policy_id) {
12869 *return_policy_id = inp->inp_policyresult.policy_id;
12870 }
12871 if (return_route_rule_id) {
12872 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12873 }
12874 if (return_skip_policy_id) {
12875 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12876 }
12877 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12878 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12879 }
12880 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12881 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",
12882 inp->inp_socket, info.bound_interface_index, info.protocol,
12883 inp->inp_policyresult.policy_id,
12884 inp->inp_policyresult.skip_policy_id,
12885 inp->inp_policyresult.results.result,
12886 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
12887 }
12888 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
12889 return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12890 }
12891 lck_rw_done(&necp_kernel_policy_lock);
12892 goto done;
12893 }
12894
12895 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
12896 size_t route_rule_id_array_count = 0;
12897 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
12898 struct necp_kernel_socket_policy *matched_policy =
12899 necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
12900 &info,
12901 &filter_control_unit,
12902 route_rule_id_array,
12903 &route_rule_id_array_count,
12904 MAX_AGGREGATE_ROUTE_RULES,
12905 &service_action,
12906 &service,
12907 netagent_ids,
12908 NECP_MAX_NETAGENTS,
12909 NULL,
12910 0,
12911 NULL,
12912 0,
12913 effective_proc,
12914 pf_tag,
12915 return_skip_policy_id,
12916 inp->inp_route.ro_rt,
12917 &drop_dest_policy_result,
12918 &drop_all_bypass,
12919 &flow_divert_aggregate_unit,
12920 so,
12921 debug);
12922
12923 // Check for loopback exception again after the policy match
12924 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
12925 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
12926 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
12927 // If policies haven't changed since last evaluation, do not update filter result in order to
12928 // preserve the very first filter result for the socket. Otherwise, update the filter result to
12929 // allow content filter to detect and drop pre-existing flows.
12930 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
12931 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
12932 if (info.soflow_entry != NULL) {
12933 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
12934 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
12935 }
12936 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
12937 current_filter_control_unit != filter_control_unit) {
12938 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12939 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12940 if (info.soflow_entry != NULL) {
12941 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
12942 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
12943 }
12944 }
12945 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12946 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12947 }
12948 allowed_to_receive = TRUE;
12949 lck_rw_done(&necp_kernel_policy_lock);
12950
12951 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);
12952 goto done;
12953 }
12954
12955 if (info.protocol != IPPROTO_UDP) {
12956 goto skip_agent_check;
12957 }
12958
12959 // Verify netagents
12960 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
12961 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12962 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);
12963 }
12964
12965 // Mark socket as a drop if required agent is not active
12966 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12967 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12968 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12969 inp->inp_policyresult.flowhash = flowhash;
12970 inp->inp_policyresult.results.filter_control_unit = 0;
12971 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
12972 inp->inp_policyresult.results.route_rule_id = 0;
12973 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
12974 if (info.soflow_entry != NULL) {
12975 info.soflow_entry->soflow_filter_control_unit = 0;
12976 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
12977 }
12978
12979 // Unlock
12980 allowed_to_receive = FALSE;
12981 lck_rw_done(&necp_kernel_policy_lock);
12982
12983 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);
12984
12985 goto done;
12986 }
12987
12988 skip_agent_check:
12989
12990 if (route_rule_id_array_count == 1) {
12991 route_rule_id = route_rule_id_array[0];
12992 } else if (route_rule_id_array_count > 1) {
12993 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
12994 }
12995
12996 bool send_local_network_denied_event = false;
12997 if (matched_policy != NULL) {
12998 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
12999 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
13000 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
13001 // Trigger the event that we dropped due to a local network policy
13002 send_local_network_denied_event = true;
13003 }
13004
13005 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
13006 matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13007 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13008 matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
13009 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13010 (route_rule_id != 0 &&
13011 !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
13012 !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
13013 allowed_to_receive = FALSE;
13014 } else {
13015 if (return_policy_id) {
13016 *return_policy_id = matched_policy->id;
13017 }
13018 if (return_route_rule_id) {
13019 *return_route_rule_id = route_rule_id;
13020 }
13021 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
13022 pass_flags = matched_policy->result_parameter.pass_flags;
13023 }
13024 // If policies haven't changed since last evaluation, do not update filter result in order to
13025 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13026 // allow content filter to detect and drop pre-existing flows.
13027 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13028 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13029 if (info.soflow_entry != NULL) {
13030 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13031 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13032 }
13033 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13034 current_filter_control_unit != filter_control_unit) {
13035 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13036 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13037 if (info.soflow_entry != NULL) {
13038 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13039 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13040 }
13041 }
13042 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13043 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13044 }
13045 }
13046
13047 if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
13048 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>",
13049 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);
13050 }
13051 } else {
13052 bool drop_all = false;
13053 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
13054 drop_all = true;
13055 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
13056 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
13057 }
13058 }
13059 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
13060 allowed_to_receive = FALSE;
13061 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
13062 } else {
13063 if (return_policy_id) {
13064 *return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13065 }
13066 if (return_route_rule_id) {
13067 *return_route_rule_id = route_rule_id;
13068 }
13069
13070 // If policies haven't changed since last evaluation, do not update filter result in order to
13071 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13072 // allow content filter to detect and drop pre-existing flows.
13073 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13074 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13075 if (info.soflow_entry != NULL) {
13076 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13077 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13078 }
13079 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13080 current_filter_control_unit != filter_control_unit) {
13081 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13082 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13083 if (info.soflow_entry != NULL) {
13084 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13085 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13086 }
13087 }
13088 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13089 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13090 }
13091 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);
13092 }
13093 }
13094
13095 if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
13096 allowed_to_receive = FALSE;
13097 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
13098 }
13099
13100 lck_rw_done(&necp_kernel_policy_lock);
13101
13102 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
13103 inp->inp_policyresult.network_denied_notifies++;
13104 #if defined(XNU_TARGET_OS_OSX)
13105 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
13106 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13107 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13108 NETPOLICY_NETWORKTYPE_LOCAL);
13109 #else
13110 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13111 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13112 NETPOLICY_NETWORKTYPE_LOCAL);
13113 #endif
13114 }
13115
13116 done:
13117 if (return_pass_flags != NULL) {
13118 *return_pass_flags = pass_flags;
13119 }
13120
13121 if (pf_tag != 0 && allowed_to_receive) {
13122 allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
13123 }
13124
13125 if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
13126 soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
13127 }
13128
13129 if (socket_proc) {
13130 proc_rele(socket_proc);
13131 }
13132
13133 if (info.soflow_entry != NULL) {
13134 soflow_free_flow(info.soflow_entry);
13135 }
13136
13137 return allowed_to_receive;
13138 }
13139
13140 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)13141 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)
13142 {
13143 struct sockaddr_in local = {};
13144 struct sockaddr_in remote = {};
13145 local.sin_family = remote.sin_family = AF_INET;
13146 local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
13147 local.sin_port = local_port;
13148 remote.sin_port = remote_port;
13149 memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
13150 memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
13151
13152 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13153 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13154 }
13155
13156 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)13157 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)
13158 {
13159 struct sockaddr_in6 local = {};
13160 struct sockaddr_in6 remote = {};
13161 local.sin6_family = remote.sin6_family = AF_INET6;
13162 local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
13163 local.sin6_port = local_port;
13164 remote.sin6_port = remote_port;
13165 memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
13166 memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
13167
13168 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13169 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13170 }
13171
13172 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)13173 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,
13174 u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13175 {
13176 return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
13177 return_policy_id, return_route_rule_id,
13178 return_skip_policy_id, return_pass_flags);
13179 }
13180
13181 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)13182 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
13183 necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
13184 {
13185 if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
13186 return EINVAL;
13187 }
13188
13189 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13190 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
13191 policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
13192 }
13193
13194 // Mark ID for Pass and IP Tunnel
13195 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13196 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13197 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
13198 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
13199 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13200 } else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
13201 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
13202 // This case is same as a PASS
13203 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13204 } else {
13205 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13206 }
13207 packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
13208 if (route_rule_id != 0) {
13209 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
13210 } else {
13211 packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13212 }
13213 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);
13214
13215 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13216 skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13217 // Only mark the skip policy if it is a valid policy ID
13218 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13219 } else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13220 inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13221 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13222 } else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
13223 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
13224 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
13225 // See necp_get_skip_policy_id_from_packet() and
13226 // necp_packet_should_skip_filters().
13227 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13228 } else {
13229 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13230 }
13231
13232 if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
13233 ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
13234 m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
13235 }
13236
13237 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13238 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
13239 packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
13240 }
13241
13242 return 0;
13243 }
13244
13245 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)13246 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
13247 {
13248 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13249 return EINVAL;
13250 }
13251
13252 // Mark ID for Pass and IP Tunnel
13253 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13254 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13255 } else {
13256 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13257 }
13258
13259 return 0;
13260 }
13261
13262 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)13263 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
13264 {
13265 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13266 return EINVAL;
13267 }
13268
13269 // Mark ID for Pass and IP Tunnel
13270 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13271 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13272 } else {
13273 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13274 }
13275
13276 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13277 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13278 } else {
13279 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13280 }
13281 return 0;
13282 }
13283
13284 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)13285 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
13286 {
13287 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13288 return EINVAL;
13289 }
13290
13291 // Mark ID for Pass and IP Tunnel
13292 if (interface != NULL) {
13293 packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
13294 }
13295
13296 return 0;
13297 }
13298
13299 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)13300 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
13301 {
13302 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13303 return EINVAL;
13304 }
13305
13306 if (is_keepalive) {
13307 packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
13308 } else {
13309 packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
13310 }
13311
13312 return 0;
13313 }
13314
13315 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)13316 necp_get_policy_id_from_packet(struct mbuf *packet)
13317 {
13318 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13319 return NECP_KERNEL_POLICY_ID_NONE;
13320 }
13321
13322 return packet->m_pkthdr.necp_mtag.necp_policy_id;
13323 }
13324
13325 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)13326 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
13327 {
13328 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13329 return NECP_KERNEL_POLICY_ID_NONE;
13330 }
13331
13332 // Check for overloaded value. See necp_mark_packet_from_socket().
13333 if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
13334 return NECP_KERNEL_POLICY_ID_NONE;
13335 }
13336
13337 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
13338 }
13339
13340 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)13341 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
13342 {
13343 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13344 return 0;
13345 }
13346
13347 return m_pftag(packet)->pftag_tag;
13348 }
13349
13350 bool
necp_packet_should_skip_filters(struct mbuf * packet)13351 necp_packet_should_skip_filters(struct mbuf *packet)
13352 {
13353 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13354 return false;
13355 }
13356
13357 // Check for overloaded value. See necp_mark_packet_from_socket().
13358 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
13359 }
13360
13361 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)13362 necp_get_last_interface_index_from_packet(struct mbuf *packet)
13363 {
13364 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13365 return 0;
13366 }
13367
13368 return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
13369 }
13370
13371 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)13372 necp_get_route_rule_id_from_packet(struct mbuf *packet)
13373 {
13374 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13375 return 0;
13376 }
13377
13378 return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
13379 }
13380
13381 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)13382 necp_get_app_uuid_from_packet(struct mbuf *packet,
13383 uuid_t app_uuid)
13384 {
13385 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13386 return EINVAL;
13387 }
13388
13389 bool found_mapping = FALSE;
13390 if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
13391 lck_rw_lock_shared(&necp_kernel_policy_lock);
13392 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);
13393 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
13394 if (entry != NULL) {
13395 uuid_copy(app_uuid, entry->uuid);
13396 found_mapping = true;
13397 }
13398 lck_rw_done(&necp_kernel_policy_lock);
13399 }
13400 if (!found_mapping) {
13401 uuid_clear(app_uuid);
13402 }
13403 return 0;
13404 }
13405
13406 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)13407 necp_get_is_keepalive_from_packet(struct mbuf *packet)
13408 {
13409 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13410 return FALSE;
13411 }
13412
13413 return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
13414 }
13415
13416 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)13417 necp_socket_get_content_filter_control_unit(struct socket *so)
13418 {
13419 struct inpcb *inp = sotoinpcb(so);
13420
13421 if (inp == NULL) {
13422 return 0;
13423 }
13424 return inp->inp_policyresult.results.filter_control_unit;
13425 }
13426
13427 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)13428 necp_socket_get_policy_gencount(struct socket *so)
13429 {
13430 struct inpcb *inp = so ? sotoinpcb(so) : NULL;
13431
13432 if (inp == NULL) {
13433 return 0;
13434 }
13435 return inp->inp_policyresult.policy_gencount;
13436 }
13437
13438 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)13439 necp_socket_should_use_flow_divert(struct inpcb *inp)
13440 {
13441 if (inp == NULL) {
13442 return FALSE;
13443 }
13444
13445 return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
13446 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13447 (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
13448 }
13449
13450 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)13451 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
13452 {
13453 if (inp == NULL) {
13454 return 0;
13455 }
13456
13457 if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13458 return 0;
13459 }
13460
13461 if (aggregate_unit != NULL &&
13462 inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13463 *aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13464 }
13465
13466 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13467 return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13468 }
13469
13470 return 0;
13471 }
13472
13473 bool
necp_socket_should_rescope(struct inpcb * inp)13474 necp_socket_should_rescope(struct inpcb *inp)
13475 {
13476 if (inp == NULL) {
13477 return FALSE;
13478 }
13479
13480 return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13481 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13482 }
13483
13484 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13485 necp_socket_get_rescope_if_index(struct inpcb *inp)
13486 {
13487 if (inp == NULL) {
13488 return 0;
13489 }
13490
13491 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13492 return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13493 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13494 return necp_get_primary_direct_interface_index();
13495 }
13496
13497 return 0;
13498 }
13499
13500 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13501 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13502 {
13503 if (inp == NULL) {
13504 return current_mtu;
13505 }
13506
13507 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13508 (inp->inp_flags & INP_BOUND_IF) &&
13509 inp->inp_boundifp) {
13510 u_int bound_interface_index = inp->inp_boundifp->if_index;
13511 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13512
13513 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13514 if (bound_interface_index != tunnel_interface_index) {
13515 ifnet_t tunnel_interface = NULL;
13516
13517 ifnet_head_lock_shared();
13518 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13519 ifnet_head_done();
13520
13521 if (tunnel_interface != NULL) {
13522 u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13523 u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13524 const char ipsec_prefix[] = "ipsec";
13525 if (delegate_tunnel_mtu != 0 &&
13526 strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13527 // For ipsec interfaces, calculate the overhead from the delegate interface
13528 u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13529 if (delegate_tunnel_mtu > tunnel_overhead) {
13530 delegate_tunnel_mtu -= tunnel_overhead;
13531 }
13532
13533 if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13534 // If the (delegate - overhead) < direct, return (delegate - overhead)
13535 return delegate_tunnel_mtu;
13536 } else {
13537 // Otherwise return direct
13538 return direct_tunnel_mtu;
13539 }
13540 } else {
13541 // For non-ipsec interfaces, just return the tunnel MTU
13542 return direct_tunnel_mtu;
13543 }
13544 }
13545 }
13546 }
13547
13548 // By default, just return the MTU passed in
13549 return current_mtu;
13550 }
13551
13552 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13553 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13554 {
13555 if (result_parameter == NULL) {
13556 return NULL;
13557 }
13558
13559 return ifindex2ifnet[result_parameter->tunnel_interface_index];
13560 }
13561
13562 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13563 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13564 {
13565 bool found_match = FALSE;
13566 bool can_rebind = FALSE;
13567 ifaddr_t ifa;
13568 union necp_sockaddr_union address_storage;
13569
13570 if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13571 return FALSE;
13572 }
13573
13574 // Match source address against interface addresses
13575 ifnet_lock_shared(interface);
13576 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13577 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13578 if (address_storage.sa.sa_family != family) {
13579 continue;
13580 }
13581
13582 if (family == AF_INET) {
13583 struct ip *ip = mtod(packet, struct ip *);
13584 if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13585 found_match = TRUE;
13586 break;
13587 }
13588 } else if (family == AF_INET6) {
13589 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13590 if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13591 found_match = TRUE;
13592 break;
13593 }
13594 }
13595 }
13596 }
13597 const uint32_t if_idx = interface->if_index;
13598 ifnet_lock_done(interface);
13599
13600 // If source address matched, attempt to construct a route to the destination address
13601 if (found_match) {
13602 ROUTE_RELEASE(new_route);
13603
13604 if (family == AF_INET) {
13605 struct ip *ip = mtod(packet, struct ip *);
13606 struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13607 dst4->sin_family = AF_INET;
13608 dst4->sin_len = sizeof(struct sockaddr_in);
13609 dst4->sin_addr = ip->ip_dst;
13610 rtalloc_scoped(new_route, if_idx);
13611 if (!ROUTE_UNUSABLE(new_route)) {
13612 can_rebind = TRUE;
13613 }
13614 } else if (family == AF_INET6) {
13615 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13616 struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13617 dst6->sin6_family = AF_INET6;
13618 dst6->sin6_len = sizeof(struct sockaddr_in6);
13619 dst6->sin6_addr = ip6->ip6_dst;
13620 rtalloc_scoped(new_route, if_idx);
13621 if (!ROUTE_UNUSABLE(new_route)) {
13622 can_rebind = TRUE;
13623 }
13624 }
13625 }
13626
13627 return can_rebind;
13628 }
13629
13630 static bool
necp_addr_is_loopback(struct sockaddr * address)13631 necp_addr_is_loopback(struct sockaddr *address)
13632 {
13633 if (address == NULL) {
13634 return FALSE;
13635 }
13636
13637 if (address->sa_family == AF_INET) {
13638 return ntohl(SIN(address)->sin_addr.s_addr) == INADDR_LOOPBACK;
13639 } else if (address->sa_family == AF_INET6) {
13640 if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13641 return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13642 } else {
13643 // Match ::ffff:127.0.0.1 loopback address
13644 in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13645 return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13646 }
13647 }
13648
13649 return FALSE;
13650 }
13651
13652 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)13653 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13654 {
13655 // Note: This function only checks for the loopback addresses.
13656 // In the future, we may want to expand to also allow any traffic
13657 // going through the loopback interface, but until then, this
13658 // check is cheaper.
13659
13660 if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13661 return TRUE;
13662 }
13663
13664 if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13665 return TRUE;
13666 }
13667
13668 if (inp != NULL) {
13669 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13670 return TRUE;
13671 }
13672 if (inp->inp_vflag & INP_IPV4) {
13673 if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
13674 ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
13675 return TRUE;
13676 }
13677 } else if (inp->inp_vflag & INP_IPV6) {
13678 if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13679 IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13680 return TRUE;
13681 }
13682 }
13683 } else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13684 return TRUE;
13685 }
13686
13687 if (packet != NULL) {
13688 struct ip *ip = mtod(packet, struct ip *);
13689 if (ip->ip_v == 4) {
13690 if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
13691 return TRUE;
13692 }
13693 if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
13694 return TRUE;
13695 }
13696 } else if (ip->ip_v == 6) {
13697 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13698 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13699 return TRUE;
13700 }
13701 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13702 return TRUE;
13703 }
13704 }
13705 }
13706
13707 return FALSE;
13708 }
13709
13710 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13711 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13712 {
13713 if (inp != NULL) {
13714 if (!(inp->inp_vflag & INP_IPV6)) {
13715 return false;
13716 }
13717 if (INP_INTCOPROC_ALLOWED(inp)) {
13718 return true;
13719 }
13720 if ((inp->inp_flags & INP_BOUND_IF) &&
13721 IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13722 return true;
13723 }
13724 return false;
13725 }
13726 if (packet != NULL) {
13727 struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13728 struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13729 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13730 NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13731 return true;
13732 }
13733 }
13734
13735 return false;
13736 }
13737
13738 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13739 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13740 {
13741 char dest_str[MAX_IPv6_STR_LEN];
13742
13743 if (necp_drop_dest_debug > 0) {
13744 if (sau->sa.sa_family == AF_INET) {
13745 (void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13746 } else if (sau->sa.sa_family == AF_INET6) {
13747 (void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13748 } else {
13749 dest_str[0] = 0;
13750 }
13751 }
13752 for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13753 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13754 struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13755
13756 if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13757 if (necp_drop_dest_debug > 0) {
13758 char subnet_str[MAX_IPv6_STR_LEN];
13759 struct proc *p = current_proc();
13760 pid_t pid = proc_pid(p);
13761
13762 if (sau->sa.sa_family == AF_INET) {
13763 (void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13764 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);
13765 } else if (sau->sa.sa_family == AF_INET6) {
13766 (void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13767 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);
13768 }
13769 }
13770 return true;
13771 }
13772 }
13773 if (necp_drop_dest_debug > 1) {
13774 struct proc *p = current_proc();
13775 pid_t pid = proc_pid(p);
13776
13777 os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13778 }
13779 return false;
13780 }
13781
13782 static int
13783 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13784 {
13785 #pragma unused(arg1, arg2, oidp)
13786 int changed = 0;
13787 int error = 0;
13788 struct necp_drop_dest_policy tmp_drop_dest_policy;
13789 struct proc *p = current_proc();
13790 pid_t pid = proc_pid(p);
13791
13792 if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13793 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13794 NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13795 return EPERM;
13796 }
13797 if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13798 NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13799 return EINVAL;
13800 }
13801
13802 memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13803 error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13804 if (error != 0) {
13805 NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13806 return error;
13807 }
13808 if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13809 return error;
13810 }
13811
13812 //
13813 // Validate the passed parameters
13814 //
13815 if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13816 NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13817 return EINVAL;
13818 }
13819 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13820 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13821 struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13822
13823 switch (tmp_drop_dest_entry->level) {
13824 case NECP_SESSION_PRIORITY_UNKNOWN:
13825 if (tmp_drop_dest_policy.entry_count != 0) {
13826 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);
13827 return EINVAL;
13828 }
13829 break;
13830 case NECP_SESSION_PRIORITY_CONTROL:
13831 case NECP_SESSION_PRIORITY_CONTROL_1:
13832 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13833 case NECP_SESSION_PRIORITY_HIGH:
13834 case NECP_SESSION_PRIORITY_HIGH_1:
13835 case NECP_SESSION_PRIORITY_HIGH_2:
13836 case NECP_SESSION_PRIORITY_HIGH_3:
13837 case NECP_SESSION_PRIORITY_HIGH_4:
13838 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13839 case NECP_SESSION_PRIORITY_DEFAULT:
13840 case NECP_SESSION_PRIORITY_LOW:
13841 if (tmp_drop_dest_policy.entry_count == 0) {
13842 NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13843 return EINVAL;
13844 }
13845 break;
13846 default: {
13847 NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13848 return EINVAL;
13849 }
13850 }
13851
13852 switch (npca->address.sa.sa_family) {
13853 case AF_INET: {
13854 if (npca->prefix > 32) {
13855 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13856 return EINVAL;
13857 }
13858 if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
13859 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
13860 return EINVAL;
13861 }
13862 if (npca->address.sin.sin_port != 0) {
13863 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);
13864 return EINVAL;
13865 }
13866 break;
13867 }
13868 case AF_INET6: {
13869 if (npca->prefix > 128) {
13870 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13871 return EINVAL;
13872 }
13873 if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
13874 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
13875 return EINVAL;
13876 }
13877 if (npca->address.sin6.sin6_port != 0) {
13878 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);
13879 return EINVAL;
13880 }
13881 if (npca->address.sin6.sin6_flowinfo != 0) {
13882 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);
13883 return EINVAL;
13884 }
13885 if (npca->address.sin6.sin6_scope_id != 0) {
13886 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);
13887 return EINVAL;
13888 }
13889 break;
13890 }
13891 default: {
13892 return EINVAL;
13893 }
13894 }
13895 }
13896
13897 //
13898 // Commit the changed policy
13899 //
13900 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
13901 memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
13902
13903 necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
13904 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13905 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13906 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13907
13908 memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
13909
13910 necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
13911 }
13912 lck_rw_done(&necp_kernel_policy_lock);
13913
13914 return 0;
13915 }
13916
13917 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])13918 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
13919 {
13920 uint16_t fam = address->sa.sa_family;
13921 memset(addr_str, 0, MAX_IPv6_STR_LEN);
13922 if (fam == AF_INET) {
13923 (void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
13924 } else if (fam == AF_INET6) {
13925 (void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
13926 }
13927 return __unsafe_null_terminated_from_indexable(addr_str);
13928 }
13929