1 /*
2 * Copyright (c) 2013-2025 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <string.h>
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/malloc.h>
34 #include <sys/kernel.h>
35 #include <sys/kern_control.h>
36 #include <sys/mbuf.h>
37 #include <sys/kpi_mbuf.h>
38 #include <sys/proc_uuid_policy.h>
39 #include <net/if.h>
40 #include <sys/domain.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/coalition.h>
45 #include <sys/ubc.h>
46 #include <sys/codesign.h>
47 #include <kern/cs_blobs.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip6.h>
50 #include <netinet/tcp.h>
51 #include <netinet/tcp_var.h>
52 #include <netinet/tcp_cache.h>
53 #include <netinet/udp.h>
54 #include <netinet/in_pcb.h>
55 #include <netinet/in_tclass.h>
56 #include <netinet6/esp.h>
57 #include <net/flowhash.h>
58 #include <net/bloom_filter.h>
59 #include <net/if_var.h>
60 #include <net/pfvar.h>
61 #if SKYWALK
62 #include <skywalk/lib/net_filter_event.h>
63 #endif /* defined(SKYWALK) */
64 #include <sys/kauth.h>
65 #include <sys/sysctl.h>
66 #include <sys/sysproto.h>
67 #include <sys/priv.h>
68 #include <sys/kern_event.h>
69 #include <sys/file_internal.h>
70 #include <IOKit/IOBSD.h>
71 #include <libkern/crypto/rand.h>
72 #include <corecrypto/cchmac.h>
73 #include <corecrypto/ccsha2.h>
74 #include <os/refcnt.h>
75 #include <mach-o/loader.h>
76 #include <net/network_agent.h>
77 #include <net/necp.h>
78 #include <netinet/flow_divert_proto.h>
79 #include <kern/socket_flows.h>
80
81 #include <net/sockaddr_utils.h>
82 #include <net/trie_utility.h>
83
84 /*
85 * NECP - Network Extension Control Policy database
86 * ------------------------------------------------
87 * The goal of this module is to allow clients connecting via a
88 * policy file descriptor to create high-level policy sessions, which
89 * are ingested into low-level kernel policies that control and tag
90 * traffic at the application, socket, and IP layers.
91 *
92 * ------------------------------------------------
93 * Sessions
94 * ------------------------------------------------
95 * Each session owns a list of session policies, each of which can
96 * specify any combination of conditions and a single result. Each
97 * session also has a priority level (such as High, Default, or Low)
98 * which is requested by the client. Based on the requested level,
99 * a session order value is assigned to the session, which will be used
100 * to sort kernel policies generated by the session. The session client
101 * can specify the sub-order for each policy it creates which will be
102 * used to further sort the kernel policies.
103 *
104 * Policy fd --> 1 necp_session --> list of necp_session_policy structs
105 *
106 * ------------------------------------------------
107 * Kernel Policies
108 * ------------------------------------------------
109 * Whenever a session send the Apply command, its policies are ingested
110 * and generate kernel policies. There are two phases of kernel policy
111 * ingestion.
112 *
113 * 1. The session policy is parsed to create kernel policies at the socket
114 * and IP layers, when applicable. For example, a policy that requires
115 * all traffic from App1 to Pass will generate a socket kernel policy to
116 * match App1 and mark packets with ID1, and also an IP policy to match
117 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
118 * resulting kernel policies are added to the global socket and IP layer
119 * policy lists.
120 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
121 * || ||
122 * \/ \/
123 * necp_kernel_socket_policies necp_kernel_ip_output_policies
124 *
125 * 2. Once the global lists of kernel policies have been filled out, each
126 * list is traversed to create optimized sub-lists ("Maps") which are used during
127 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
128 * which hashes incoming packets based on marked socket-layer policies, and removes
129 * duplicate or overlapping policies. Socket policies are sent into two maps,
130 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
131 * The app layer map is used for policy checks coming in from user space, and is one
132 * list with duplicate and overlapping policies removed. The socket map hashes based
133 * on app UUID, and removes duplicate and overlapping policies.
134 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
135 * |-> necp_kernel_socket_policies_map
136 *
137 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
138 *
139 * ------------------------------------------------
140 * Drop All Level
141 * ------------------------------------------------
142 * The Drop All Level is a sysctl that controls the level at which policies are allowed
143 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
144 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
145 * by a session with a priority level better than (numerically less than) the
146 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
147 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
148 * session orders to be dropped.
149 */
150
151 u_int32_t necp_drop_all_order = 0;
152 u_int32_t necp_drop_all_level = 0;
153
154 u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
155 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
156 u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
157 u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
158 u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
159
160 u_int32_t necp_drop_unentitled_order = 0;
161 #ifdef XNU_TARGET_OS_WATCH
162 u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
163 #else // XNU_TARGET_OS_WATCH
164 u_int32_t necp_drop_unentitled_level = 0;
165 #endif // XNU_TARGET_OS_WATCH
166
167 u_int32_t necp_drop_management_order = 0;
168 u_int32_t necp_drop_management_level = NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL;
169
170 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
171
172 os_log_t necp_log_handle = NULL;
173 os_log_t necp_data_trace_log_handle = NULL;
174
175 u_int32_t necp_session_count = 0;
176 u_int32_t necp_trie_count = 0;
177
178 static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
179 struct necp_session_policy, NET_KT_DEFAULT);
180 static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
181 struct necp_kernel_socket_policy, NET_KT_DEFAULT);
182 static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
183 struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
184
185 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
186 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
187 LIST_INSERT_HEAD((head), elm, field); \
188 } else { \
189 LIST_FOREACH(tmpelm, head, field) { \
190 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
191 LIST_INSERT_AFTER(tmpelm, elm, field); \
192 break; \
193 } \
194 } \
195 } \
196 } while (0)
197
198 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
199 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
200 LIST_INSERT_HEAD((head), elm, field); \
201 } else { \
202 LIST_FOREACH(tmpelm, head, field) { \
203 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield))) { \
204 LIST_INSERT_AFTER(tmpelm, elm, field); \
205 break; \
206 } \
207 } \
208 } \
209 } while (0)
210
211 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
212 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield == (elm)->secondsortfield) && (LIST_FIRST(head)->thirdsortfield >= (elm)->thirdsortfield))) { \
213 LIST_INSERT_HEAD((head), elm, field); \
214 } else { \
215 LIST_FOREACH(tmpelm, head, field) { \
216 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield == (elm)->secondsortfield) && (LIST_NEXT(tmpelm, field)->thirdsortfield >= (elm)->thirdsortfield))) { \
217 LIST_INSERT_AFTER(tmpelm, elm, field); \
218 break; \
219 } \
220 } \
221 } \
222 } while (0)
223
224 #define IS_NECP_ROUTE_RULE_DENY(x) ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE)
225
226 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x) (IS_NECP_ROUTE_RULE_DENY(x) || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
227
228 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x000001
229 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x000002
230 #define NECP_KERNEL_CONDITION_PROTOCOL 0x000004
231 #define NECP_KERNEL_CONDITION_LOCAL_START 0x000008
232 #define NECP_KERNEL_CONDITION_LOCAL_END 0x000010
233 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x000020
234 #define NECP_KERNEL_CONDITION_REMOTE_START 0x000040
235 #define NECP_KERNEL_CONDITION_REMOTE_END 0x000080
236 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x000100
237 #define NECP_KERNEL_CONDITION_APP_ID 0x000200
238 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x000400
239 #define NECP_KERNEL_CONDITION_DOMAIN 0x000800
240 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x001000
241 #define NECP_KERNEL_CONDITION_POLICY_ID 0x002000
242 #define NECP_KERNEL_CONDITION_PID 0x004000
243 #define NECP_KERNEL_CONDITION_UID 0x008000
244 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x010000 // Only set from packets looping between interfaces
245 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x020000
246 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x040000
247 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 0x080000
248 #define NECP_KERNEL_CONDITION_AGENT_TYPE 0x100000
249 #define NECP_KERNEL_CONDITION_HAS_CLIENT 0x200000
250 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS 0x400000
251 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS 0x800000
252 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY 0x1000000
253 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY 0x2000000
254 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY 0x4000000
255 #define NECP_KERNEL_CONDITION_SDK_VERSION 0x8000000
256 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x10000000
257 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 0x20000000
258 #define NECP_KERNEL_CONDITION_IS_LOOPBACK 0x40000000
259 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY 0x80000000
260 #define NECP_KERNEL_CONDITION_SCHEME_PORT 0x100000000
261 #define NECP_KERNEL_CONDITION_DOMAIN_FILTER 0x200000000
262 #define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT 0x400000000
263 #define NECP_KERNEL_CONDITION_EXACT_DOMAIN 0x800000000
264 #define NECP_KERNEL_CONDITION_REAL_UID 0x1000000000
265 #define NECP_KERNEL_CONDITION_URL 0x2000000000
266 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS 0x4000000000
267
268 #define NECP_MAX_POLICY_RESULT_SIZE 512
269 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
270 #define NECP_MAX_CONDITIONS_ARRAY_SIZE 4096
271 #define NECP_MAX_POLICY_LIST_COUNT 1024
272
273 #define NECP_MAX_DOMAIN_FILTER_SIZE 65536 // Allows room for 100K domains
274 #define NECP_MAX_DOMAIN_TRIE_SIZE (1024 * 512) // Allows 5000+ domains
275
276 typedef enum {
277 NECP_BYPASS_TYPE_NONE = 0,
278 NECP_BYPASS_TYPE_INTCOPROC = 1,
279 NECP_BYPASS_TYPE_LOOPBACK = 2,
280 NECP_BYPASS_TYPE_DROP = 3, // Drop now without hitting necp policies
281 } necp_socket_bypass_type_t;
282
283 // Cap the policy size at the max result + conditions size, with room for extra TLVs
284 #define NECP_MAX_POLICY_SIZE (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
285
286 struct necp_service_registration {
287 LIST_ENTRY(necp_service_registration) session_chain;
288 LIST_ENTRY(necp_service_registration) kernel_chain;
289 u_int32_t service_id;
290 };
291
292 struct necp_domain_filter {
293 LIST_ENTRY(necp_domain_filter) owner_chain;
294 LIST_ENTRY(necp_domain_filter) chain;
295 u_int32_t id;
296 struct net_bloom_filter *filter;
297 os_refcnt_t refcount;
298 };
299 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
300
301 /*
302 * Filter id space is split between domain bloom filter id and domain trie filter id.
303 * id <= 10000 - bloom filter ids
304 * id > 10000 - trie filter ids
305 */
306 #define NECP_DOMAIN_FILTER_ID_MAX 10000
307 #define NECP_DOMAIN_TRIE_ID_START NECP_DOMAIN_FILTER_ID_MAX
308 #define NECP_IS_DOMAIN_FILTER_ID(id) (id <= NECP_DOMAIN_FILTER_ID_MAX)
309
310 struct necp_domain_trie {
311 LIST_ENTRY(necp_domain_trie) owner_chain;
312 LIST_ENTRY(necp_domain_trie) chain;
313 u_int32_t id;
314 struct necp_domain_trie_request *trie_request;
315 size_t trie_request_size;
316 struct net_trie trie;
317 os_refcnt_t refcount;
318 };
319 static LIST_HEAD(necp_domain_trie_list, necp_domain_trie) necp_global_domain_trie_list;
320
321 struct necp_session {
322 u_int8_t necp_fd_type;
323 u_int32_t control_unit;
324 u_int32_t session_priority; // Descriptive priority rating
325 u_int32_t session_order;
326
327 necp_policy_id last_policy_id;
328
329 decl_lck_mtx_data(, lock);
330
331 bool proc_locked; // Messages must come from proc_uuid
332 uuid_t proc_uuid;
333 int proc_pid;
334
335 bool dirty;
336 LIST_HEAD(_policies, necp_session_policy) policies;
337
338 LIST_HEAD(_services, necp_service_registration) services;
339 struct necp_domain_filter_list domain_filters;
340 struct necp_domain_trie_list domain_tries;
341
342 TAILQ_ENTRY(necp_session) chain;
343 };
344
345 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
346 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
347
348 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
349
350 struct necp_socket_info {
351 pid_t pid;
352 int32_t pid_version;
353 uid_t uid;
354 uid_t real_uid;
355 union necp_sockaddr_union local_addr;
356 union necp_sockaddr_union remote_addr;
357 u_int32_t bound_interface_index;
358 u_int32_t bound_interface_flags;
359 u_int32_t bound_interface_eflags;
360 u_int32_t bound_interface_xflags;
361 u_int32_t traffic_class;
362 u_int16_t protocol;
363 u_int16_t scheme_port;
364 u_int32_t application_id;
365 u_int32_t real_application_id;
366 u_int32_t account_id;
367 u_int32_t drop_order;
368 u_int32_t client_flags;
369 char *domain __null_terminated;
370 char *url __null_terminated;
371 struct soflow_hash_entry *soflow_entry;
372 unsigned is_entitled : 1;
373 unsigned has_client : 1;
374 unsigned has_system_signed_result : 1;
375 unsigned is_platform_binary : 1;
376 unsigned used_responsible_pid : 1;
377 unsigned is_loopback : 1;
378 unsigned real_is_platform_binary : 1;
379 unsigned is_delegated : 1;
380 unsigned is_local : 1;
381 unsigned __pad_bits : 7;
382 };
383
384 static LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
385 static LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
386 static LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
387 &necp_kernel_policy_mtx_attr);
388
389 static LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
390 static LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
391
392 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
393
394 /*
395 * On modification, invalidate cached lookups by bumping the generation count.
396 * Other calls will need to take the slowpath of taking
397 * the subsystem lock.
398 */
399 static volatile int32_t necp_kernel_socket_policies_gencount;
400 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
401 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
402 necp_kernel_socket_policies_gencount = 1; \
403 } \
404 } while (0)
405
406 /*
407 * Drop-all Bypass:
408 * Allow priviledged processes to bypass the default drop-all
409 * via entitlement check. For OSX, since entitlement check is
410 * not supported for configd, configd signing identity is checked
411 * instead.
412 */
413 #define SIGNING_ID_CONFIGD "com.apple.configd"
414 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
415
416 typedef enum {
417 NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
418 NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
419 NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
420 } necp_drop_all_bypass_check_result_t;
421
422 static u_int64_t necp_kernel_application_policies_condition_mask;
423 static size_t necp_kernel_application_policies_count;
424 static u_int64_t necp_kernel_socket_policies_condition_mask;
425 static size_t necp_kernel_socket_policies_count;
426 static size_t necp_kernel_socket_policies_non_app_count;
427 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
428 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
429 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
430 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
431 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
432 static size_t necp_kernel_socket_policies_app_layer_map_count;
433 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_app_layer_map;
434 /*
435 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
436 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
437 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
438 *
439 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
440 */
441
442 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
443 static size_t necp_kernel_ip_output_policies_count;
444 static size_t necp_kernel_ip_output_policies_non_id_count;
445 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
446 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
447 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
448 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
449 static struct necp_kernel_ip_output_policy ** __indexable necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
450 static struct necp_kernel_socket_policy pass_policy =
451 {
452 .id = NECP_KERNEL_POLICY_ID_NO_MATCH,
453 .result = NECP_KERNEL_POLICY_RESULT_PASS,
454 };
455
456 static struct necp_session *necp_create_session(void);
457 static void necp_delete_session(struct necp_session *session);
458
459 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
460 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
461 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
462
463 #define MAX_RESULT_STRING_LEN 64
464 static inline const char * __sized_by(MAX_RESULT_STRING_LEN) necp_get_result_description(char * __sized_by(MAX_RESULT_STRING_LEN) result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
465
466 static struct necp_session_policy *necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *__sized_by(conditions_array_size)conditions_array, u_int32_t conditions_array_size, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, u_int8_t * __sized_by(result_size)result, u_int32_t result_size);
467 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
468 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
469 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
470 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
471 static void necp_policy_apply_all(struct necp_session *session);
472
473 static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement __null_terminated, u_int32_t cond_account_id, char *cond_domain __null_terminated, u_int32_t cond_domain_filter, char *cond_url __null_terminated, pid_t cond_pid, int32_t cond_pid_version, uid_t cond_uid, uid_t cond_real_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union * __single cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier __null_terminated, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
474 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
475 static bool necp_kernel_socket_policies_reprocess(void);
476 static bool necp_kernel_socket_policies_update_uuid_table(void);
477 static inline struct necp_kernel_socket_policy * necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
478 struct necp_socket_info *info,
479 necp_kernel_policy_filter *return_filter,
480 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
481 size_t *return_route_rule_id_array_count,
482 size_t route_rule_id_array_count,
483 necp_kernel_policy_result *return_service_action,
484 necp_kernel_policy_service *return_service,
485 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
486 size_t netagent_array_count,
487 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
488 size_t netagent_use_flags_array_count,
489 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
490 u_int32_t num_required_agent_types,
491 proc_t proc,
492 u_int16_t pf_tag,
493 necp_kernel_policy_id *skip_policy_id,
494 struct rtentry *rt,
495 necp_kernel_policy_result *return_drop_dest_policy_result,
496 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
497 u_int32_t *return_flow_divert_aggregate_unit,
498 struct socket *so,
499 int debug);
500 static necp_kernel_policy_id necp_kernel_ip_output_policy_add(necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_kernel_policy_id cond_policy_id, ifnet_t cond_bound_interface, u_int32_t cond_last_interface_index, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
501 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
502 static bool necp_kernel_ip_output_policies_reprocess(void);
503
504 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
505 static bool necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end);
506 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
507 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
508 static bool necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits);
509 static bool necp_addr_is_empty(struct sockaddr *addr);
510 static bool necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index);
511 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
512
513 struct necp_uuid_id_mapping {
514 LIST_ENTRY(necp_uuid_id_mapping) chain;
515 uuid_t uuid;
516 u_int32_t id;
517 os_refcnt_t refcount;
518 u_int32_t table_usecount; // Add to UUID policy table count
519 };
520 static size_t necp_num_uuid_app_id_mappings;
521 static bool necp_uuid_app_id_mappings_dirty;
522 #define NECP_UUID_APP_ID_HASH_SIZE 64
523 static u_long necp_uuid_app_id_hash_mask;
524 static u_long necp_uuid_app_id_hash_num_buckets;
525 static LIST_HEAD(necp_uuid_id_mapping_head, necp_uuid_id_mapping) * __counted_by(necp_uuid_app_id_hash_num_buckets) necp_uuid_app_id_hashtbl, necp_uuid_service_id_list; // App map is real hash table, service map is just mapping
526 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
527 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
528 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
529 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
530
531 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
532 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
533 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
534 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
535 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
536
537 struct necp_string_id_mapping {
538 LIST_ENTRY(necp_string_id_mapping) chain;
539 char *string __null_terminated;
540 necp_app_id id;
541 os_refcnt_t refcount;
542 };
543 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
544 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
545 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
546 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
547
548 static u_int32_t necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter);
549 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
550 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
551
552 static u_int32_t necp_create_domain_trie(struct necp_domain_trie_list *list, struct necp_domain_trie_list *owner_list,
553 struct necp_domain_trie_request *necp_trie_request, size_t necp_trie_request_size);
554 static bool necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id);
555 static void necp_free_domain_trie(struct necp_domain_trie *trie);
556 static struct necp_domain_trie *necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id);
557 static Boolean necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length);
558
559 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
560 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
561
562 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
563
564 static char * __null_terminated necp_create_trimmed_domain(char * __sized_by(length)string, size_t length);
565 static inline int necp_count_dots(char * __sized_by(length)string, size_t length);
566
567 static char * __null_terminated necp_copy_string(char * __sized_by(length)string, size_t length);
568 static bool necp_update_qos_marking(struct ifnet *ifp, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id);
569
570 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
571
572 #define MAX_ROUTE_RULE_INTERFACES 10
573 struct necp_route_rule {
574 LIST_ENTRY(necp_route_rule) chain;
575 u_int32_t id;
576 u_int32_t netagent_id;
577 u_int32_t control_unit;
578 u_int32_t match_netagent_id;
579 u_int32_t effective_type;
580 u_int8_t default_action;
581 u_int8_t cellular_action;
582 u_int8_t wifi_action;
583 u_int8_t wired_action;
584 u_int8_t expensive_action;
585 u_int8_t constrained_action;
586 u_int8_t companion_action;
587 u_int8_t vpn_action;
588 u_int exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
589 u_int8_t exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
590 os_refcnt_t refcount;
591 };
592 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
593 static u_int32_t necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, bool *has_socket_only_actions);
594 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
595 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
596 static bool necp_route_is_allowed(struct rtentry *route, ifnet_t interface, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count,
597 u_int32_t route_rule_id, u_int32_t *interface_type_denied);
598 static uint32_t necp_route_get_netagent(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove);
599 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
600 static uint32_t necp_route_get_flow_divert(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, u_int32_t *flow_divert_aggregate_unit);
601 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
602 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
603
604 #define MAX_AGGREGATE_ROUTE_RULES 16
605 struct necp_aggregate_route_rule {
606 LIST_ENTRY(necp_aggregate_route_rule) chain;
607 u_int32_t id;
608 u_int32_t rule_ids[MAX_AGGREGATE_ROUTE_RULES];
609 };
610 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
611 static u_int32_t necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids);
612
613 // Sysctl definitions
614 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
615 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
616 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
617
618 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
619 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
620 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
621 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
622 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
623 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
624 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
625 SYSCTL_PROC(_net_necp, NECPCTL_DROP_UNENTITLED_LEVEL, drop_unentitled_level, CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_unentitled_level, 0, &sysctl_handle_necp_unentitled_level, "IU", "");
626 SYSCTL_PROC(_net_necp, NECPCTL_DROP_MANAGEMENT_LEVEL, drop_management_level, CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_management_level, 0, &sysctl_handle_necp_management_level, "IU", "");
627 SYSCTL_PROC(_net_necp, NECPCTL_DROP_ALL_LEVEL, drop_all_level, CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_all_level, 0, &sysctl_handle_necp_level, "IU", "");
628 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
629 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_NON_APP_POLICY_COUNT, socket_non_app_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_non_app_count, "");
630 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
631 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
632 SYSCTL_INT(_net_necp, NECPCTL_TRIE_COUNT, trie_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_trie_count, 0, "");
633
634 static struct necp_drop_dest_policy necp_drop_dest_policy;
635 static int necp_drop_dest_debug = 0; // 0: off, 1: match, >1: every evaluation
636 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
637
638 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
639 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
640 0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
641
642 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
643
644 /*
645 * data tracing control -
646 *
647 * necp_data_tracing_level : 1 for brief trace, 2 for policy details, 3 for condition details
648 * necp_data_tracing_port : match traffic with specified port
649 * necp_data_tracing_proto : match traffic with specified protocol
650 * necp_data_tracing_pid : match traffic with specified pid (only applied at socket level)
651 * necp_data_tracing_ifindex : match traffic on specified ifindex
652 * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched. Default is 0 to trace traffic if any specified attributes matched.
653 * data_tracing_session_order : match policies in the specified session - log traffic that hit these policies
654 * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
655 */
656 static int necp_data_tracing_level = 0;
657 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
658
659 static int necp_data_tracing_port = 0;
660 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
661
662 static int necp_data_tracing_proto = 0;
663 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
664
665 static int necp_data_tracing_pid = 0;
666 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
667
668 static int necp_data_tracing_ifindex = 0;
669 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
670
671 static int necp_data_tracing_match_all = 0;
672 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
673
674 static int necp_data_tracing_session_order = 0;
675 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
676
677 static int necp_data_tracing_policy_order = 0;
678 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
679
680 #define NECP_DATA_TRACE_LEVEL_BRIEF 1
681 #define NECP_DATA_TRACE_LEVEL_POLICY 2
682 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
683 #define NECP_DATA_TRACE_LEVEL_DP 4
684
685 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
686 (pid == necp_data_tracing_pid)
687 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
688 (protocol == necp_data_tracing_proto)
689 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
690 (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
691 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
692 (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
693 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
694 (ifindex == necp_data_tracing_ifindex)
695
696 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
697 ((necp_data_tracing_level && \
698 ((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
699 (necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
700 (necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
701 (necp_data_tracing_port && (NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) || NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr))))) ? necp_data_tracing_level : 0)
702
703 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
704 ((necp_data_tracing_level && \
705 ((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
706 (!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
707 (!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
708 (!necp_data_tracing_port || (NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) || NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr))))) ? necp_data_tracing_level : 0)
709
710 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
711 (necp_data_tracing_match_all ? \
712 NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
713 NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
714
715 #define NECP_DATA_TRACE_ON(debug) (debug)
716 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
717 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
718 #define NECP_DATA_TRACE_DP_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_CONDITION)
719
720 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
721
722 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
723 if (NECP_DATA_TRACE_ON(debug)) { \
724 char laddr_str[MAX_IPv6_STR_LEN]; \
725 char raddr_str[MAX_IPv6_STR_LEN]; \
726 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> <policy_id %d skip_policy_id %d>", \
727 caller, log_msg, info.local_addr.sin.sin_family, info.protocol, ntohs(info.local_addr.sin.sin_port), ntohs(info.local_addr.sin6.sin6_port), ntohs(info.remote_addr.sin.sin_port), ntohs(info.remote_addr.sin6.sin6_port), necp_get_address_string(&info.local_addr, laddr_str), necp_get_address_string(&info.remote_addr, raddr_str), necp_drop_all_order, info.pid, info.application_id, info.real_application_id, info.bound_interface_index, policy_id, skip_policy_id); \
728 }
729
730 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
731 if (NECP_DATA_TRACE_ON(debug)) { \
732 char laddr_str[MAX_IPv6_STR_LEN]; \
733 char raddr_str[MAX_IPv6_STR_LEN]; \
734 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> <policy_id %d skip_policy_id %d result %d>", \
735 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, info.local_addr.sin.sin_family, info.protocol, ntohs(info.local_addr.sin.sin_port), ntohs(info.local_addr.sin6.sin6_port), ntohs(info.remote_addr.sin.sin_port), ntohs(info.remote_addr.sin6.sin6_port), necp_get_address_string(&info.local_addr, laddr_str), necp_get_address_string(&info.remote_addr, raddr_str), necp_drop_all_order, info.pid, info.application_id, info.real_application_id, info.bound_interface_index, policy_id, skip_policy_id, inp ? inp->inp_policyresult.results.result : 0); \
736 }
737
738 #define NECP_DATA_TRACE_LOG_SOCKET_DP(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
739 if (NECP_DATA_TRACE_ON(debug)) { \
740 char laddr_str[MAX_IPv6_STR_LEN]; \
741 char raddr_str[MAX_IPv6_STR_LEN]; \
742 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> <policy_id %d skip_policy_id %d result %d> <input ifindex %d> <allowed_to_receive %d><pf_tag %X pass_flags %X>", \
743 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, info.local_addr.sin.sin_family, info.protocol, ntohs(info.local_addr.sin.sin_port), ntohs(info.local_addr.sin6.sin6_port), ntohs(info.remote_addr.sin.sin_port), ntohs(info.remote_addr.sin6.sin6_port), necp_get_address_string(&info.local_addr, laddr_str), necp_get_address_string(&info.remote_addr, raddr_str), necp_drop_all_order, info.pid, info.application_id, info.real_application_id, info.bound_interface_index, policy_id, skip_policy_id, inp ? inp->inp_policyresult.results.result : 0, verifyifindex, allowed_to_receive, pf_tag, pass_flags); \
744 }
745
746 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
747 if (NECP_DATA_TRACE_ON(debug)) { \
748 char laddr_str[MAX_IPv6_STR_LEN]; \
749 char raddr_str[MAX_IPv6_STR_LEN]; \
750 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> (policy id=%d session_order=%d policy_order=%d result=%s)", \
751 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, info->local_addr.sin.sin_family, info->protocol, ntohs(info->local_addr.sin.sin_port), ntohs(info->local_addr.sin6.sin6_port), ntohs(info->remote_addr.sin.sin_port), ntohs(info->remote_addr.sin6.sin6_port), necp_get_address_string(&info->local_addr, laddr_str), necp_get_address_string(&info->remote_addr, raddr_str), necp_drop_all_order, info->pid, info->application_id, info->real_application_id, info->bound_interface_index, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result]); \
752 }
753
754 #define NECP_DATA_TRACE_LOG_SOCKET_BRIEF(debug, socket, caller, log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id) \
755 if (NECP_DATA_TRACE_ON(debug)) { \
756 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - <policy_id %d skip_policy_id %d> <cached policy_id %d skip_policy_id %d>", \
757 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id); \
758 }
759
760 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
761 if (NECP_DATA_TRACE_ON(debug)) { \
762 char laddr_str[MAX_IPv6_STR_LEN]; \
763 char raddr_str[MAX_IPv6_STR_LEN]; \
764 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <BoundInterface %d> <socket policy id %d socket skip id %d> <mbuf %X len %d %d>", \
765 caller, log_msg, local_addr.sin.sin_family, protocol, ntohs(local_addr.sin.sin_port), ntohs(local_addr.sin6.sin6_port), ntohs(remote_addr.sin.sin_port), ntohs(remote_addr.sin6.sin6_port), necp_get_address_string(&local_addr, laddr_str), necp_get_address_string(&remote_addr, raddr_str), necp_drop_all_order, bound_interface_index, socket_policy_id, socket_skip_policy_id, (unsigned int)packet, ip->ip_len, ntohs(ip->ip_len)); \
766 }
767
768 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
769 if (NECP_DATA_TRACE_ON(debug)) { \
770 char laddr_str[MAX_IPv6_STR_LEN]; \
771 char raddr_str[MAX_IPv6_STR_LEN]; \
772 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <BoundInterface %d> <socket policy id %d socket skip id %d> <mbuf %X len %d %d %d>", \
773 caller, log_msg, local_addr.sin.sin_family, protocol, ntohs(local_addr.sin.sin_port), ntohs(local_addr.sin6.sin6_port), ntohs(remote_addr.sin.sin_port), ntohs(remote_addr.sin6.sin6_port), necp_get_address_string(&local_addr, laddr_str), necp_get_address_string(&remote_addr, raddr_str), necp_drop_all_order, bound_interface_index, socket_policy_id, socket_skip_policy_id, (unsigned int)packet, ip6->ip6_plen, ntohs(ip6->ip6_plen), packet ? packet->m_pkthdr.len : 0); \
774 }
775
776 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
777 if (NECP_DATA_TRACE_ON(debug)) { \
778 char laddr_str[MAX_IPv6_STR_LEN]; \
779 char raddr_str[MAX_IPv6_STR_LEN]; \
780 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <BoundInterface %d> (policy id=%d session_order=%d policy_order=%d result=%s)", \
781 caller, log_msg, local_addr->sin.sin_family, protocol, ntohs(local_addr->sin.sin_port), ntohs(local_addr->sin6.sin6_port), ntohs(remote_addr->sin.sin_port), ntohs(remote_addr->sin6.sin6_port), necp_get_address_string(local_addr, laddr_str), necp_get_address_string(remote_addr, raddr_str), necp_drop_all_order, bound_interface_index, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result]); \
782 }
783
784 #define NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, socket, caller, log_msg) \
785 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
786 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - policy id=%d session_order=%d policy_order=%d result=%s (cond_policy_id %d) (skip_session_order %d skip_order %d)", \
787 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result], policy_search_array[i]->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID ? policy_search_array[i]->cond_policy_id : 0, skip_session_order, skip_order); \
788 }
789
790 #define NECP_DATA_TRACE_LOG_POLICY_IP(debug, caller, log_msg) \
791 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
792 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - policy id=%d session_order=%d policy_order=%d result=%s (cond_policy_id %d) (skip_session_order %d skip_order %d)", \
793 caller, log_msg, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result], policy_search_array[i]->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID ? policy_search_array[i]->cond_policy_id : 0, skip_session_order, skip_order); \
794 }
795
796 #define NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
797 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
798 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value (%d / 0x%X) (%d / 0x%X) (%d / 0x%X) input (%d / 0x%X) (%d / 0x%X) (%d / 0x%X)>", \
799 caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
800 }
801
802 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
803 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
804 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
805 caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
806 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
807 }
808
809 #define NECP_DATA_TRACE_LOG_CONDITION_IP(debug, caller, negate, name, val, input) \
810 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
811
812 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR(debug, caller, negate, name, val, input) \
813 NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
814
815
816 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
817 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
818 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value (%d / 0x%X) (%d / 0x%X) (%d / 0x%X) input (%d / 0x%X) (%d / 0x%X) (%d / 0x%X)>", \
819 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
820 }
821
822 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
823 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
824 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
825 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
826 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
827 }
828
829 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, caller, negate, name, val, input) \
830 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val, 0, 0, input, 0, 0)
831
832 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, caller, negate, name, val, input) \
833 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
834
835 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
836 (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
837 addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
838
839 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
840 "INVALID",
841 "PASS",
842 "SKIP",
843 "DROP",
844 "SOCKET_DIVERT",
845 "SOCKET_FILTER",
846 "IP_TUNNEL",
847 "IP_FILTER",
848 "TRIGGER",
849 "TRIGGER_IF_NEEDED",
850 "TRIGGER_SCOPED",
851 "NO_TRIGGER_SCOPED",
852 "SOCKET_SCOPED",
853 "ROUTE_RULES",
854 "USE_NETAGENT",
855 "NETAGENT_SCOPED",
856 "SCOPED_DIRECT",
857 "ALLOW_UNENTITLED",
858 "REMOVE_NETAGENT"
859 };
860
861
862 #define NECP_DDE_ENTITLEMENT "com.apple.developer.media-device-discovery-extension"
863
864 static int necp_drop_loopback_count = 0;
865 SYSCTL_INT(_net_necp, OID_AUTO, drop_loopback_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_drop_loopback_count, 0, "");
866
867 static bool
necp_address_is_local_interface_address(union necp_sockaddr_union * addr)868 necp_address_is_local_interface_address(union necp_sockaddr_union *addr)
869 {
870 bool is_interface_address = false;
871 if (addr == NULL) {
872 return false;
873 }
874
875 // Clean up the address before comparison with interface addresses
876 // Transform remote_addr into the ifaddr form
877 // IPv6 Scope IDs are always embedded in the ifaddr list
878 struct sockaddr_storage remote_address_sanitized;
879 u_int ifscope = IFSCOPE_NONE;
880 (void)sa_copy(SA(addr), &remote_address_sanitized, &ifscope);
881 SIN(&remote_address_sanitized)->sin_port = 0;
882 if (remote_address_sanitized.ss_family == AF_INET6) {
883 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
884 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
885 }
886 }
887
888 // Check if remote address is an interface address
889 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
890 if (ifa != NULL && ifa->ifa_ifp != NULL) {
891 is_interface_address = true;
892 }
893 if (ifa != NULL) {
894 ifaddr_release(ifa);
895 ifa = NULL;
896 }
897
898 return is_interface_address;
899 }
900
901 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, addr, include_local_addresses) \
902 ((rt) != NULL && !((rt)->rt_flags & RTF_GATEWAY) && (include_local_addresses || !((rt)->rt_flags & RTF_LOCAL)) && ((rt)->rt_ifa && (rt)->rt_ifa->ifa_ifp && !((rt)->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT) && !((rt)->rt_ifa->ifa_ifp->if_eflags & IFEF_DIRECTLINK)) && (include_local_addresses || addr == NULL || !necp_address_is_local_interface_address(addr)))
903
904 // Session order allocation
905 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)906 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
907 {
908 u_int32_t new_order = 0;
909
910 // For now, just allocate 1000 orders for each priority
911 if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
912 priority = NECP_SESSION_PRIORITY_DEFAULT;
913 }
914
915 // Use the control unit to decide the offset into the priority list
916 new_order = (control_unit) + ((priority - 1) * 1000);
917
918 return new_order;
919 }
920
921 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)922 necp_get_first_order_for_priority(u_int32_t priority)
923 {
924 if (priority == 0) {
925 return 0;
926 }
927 return ((priority - 1) * 1000) + 1;
928 }
929
930 // Sysctl handler
931 static int
932 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
933 {
934 #pragma unused(arg1, arg2)
935 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
936 necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
937 return error;
938 }
939
940 static int
941 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
942 {
943 #pragma unused(arg1, arg2)
944 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
945 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
946 return error;
947 }
948
949 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
950 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)951 _necp_process_drop_order_inner(kauth_cred_t cred)
952 {
953 if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
954 priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
955 return necp_drop_unentitled_order;
956 } else {
957 return 0;
958 }
959 }
960
961 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
962 #pragma GCC poison _necp_process_drop_order_inner
963
964 static int
965 sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS
966 {
967 #pragma unused(arg1, arg2)
968 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
969 necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
970 return error;
971 }
972
973 static inline bool
necp_socket_is_connected(struct inpcb * inp)974 necp_socket_is_connected(struct inpcb *inp)
975 {
976 return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
977 }
978
979
980 // Session fd
981
982 static int necp_session_op_close(struct fileglob *, vfs_context_t);
983
984 static const struct fileops necp_session_fd_ops = {
985 .fo_type = DTYPE_NETPOLICY,
986 .fo_read = fo_no_read,
987 .fo_write = fo_no_write,
988 .fo_ioctl = fo_no_ioctl,
989 .fo_select = fo_no_select,
990 .fo_close = necp_session_op_close,
991 .fo_drain = fo_no_drain,
992 .fo_kqfilter = fo_no_kqfilter,
993 };
994
995 static inline int
necp_is_platform_binary(proc_t proc)996 necp_is_platform_binary(proc_t proc)
997 {
998 return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
999 }
1000
1001 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)1002 necp_check_drop_all_bypass_result(proc_t proc)
1003 {
1004 if (proc == NULL) {
1005 proc = current_proc();
1006 if (proc == NULL) {
1007 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1008 }
1009 }
1010
1011 #if defined(XNU_TARGET_OS_OSX)
1012 const char *signing_id __null_terminated = NULL;
1013 const bool isConfigd = (necp_is_platform_binary(proc) &&
1014 (signing_id = cs_identity_get(proc)) &&
1015 (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
1016 (strcmp(signing_id, SIGNING_ID_CONFIGD) == 0));
1017 if (isConfigd) {
1018 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1019 }
1020 #endif
1021
1022 const task_t __single task = proc_task(proc);
1023 if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
1024 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1025 } else {
1026 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1027 }
1028 }
1029
1030 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)1031 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
1032 {
1033 #pragma unused(uap)
1034 int error = 0;
1035 struct necp_session *session = NULL;
1036 struct fileproc * __single fp = NULL;
1037 int fd = -1;
1038 uid_t uid = kauth_cred_getuid(kauth_cred_get());
1039
1040 if (!necp_is_platform_binary(p)) {
1041 NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
1042 error = EACCES;
1043 goto done;
1044 }
1045
1046 if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
1047 NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
1048 error = EACCES;
1049 goto done;
1050 }
1051
1052 error = falloc(p, &fp, &fd);
1053 if (error != 0) {
1054 goto done;
1055 }
1056
1057 session = necp_create_session();
1058 if (session == NULL) {
1059 error = ENOMEM;
1060 goto done;
1061 }
1062
1063 fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
1064 fp->fp_glob->fg_flag = 0;
1065 fp->fp_glob->fg_ops = &necp_session_fd_ops;
1066 fp_set_data(fp, session);
1067
1068 proc_fdlock(p);
1069 procfdtbl_releasefd(p, fd, NULL);
1070 fp_drop(p, fd, fp, 1);
1071 proc_fdunlock(p);
1072
1073 *retval = fd;
1074 done:
1075 if (error != 0) {
1076 if (fp != NULL) {
1077 fp_free(p, fd, fp);
1078 fp = NULL;
1079 }
1080 }
1081
1082 return error;
1083 }
1084
1085 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)1086 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
1087 {
1088 #pragma unused(ctx)
1089 struct necp_session *session = (struct necp_session *)fg_get_data(fg);
1090 fg_set_data(fg, NULL);
1091
1092 if (session != NULL) {
1093 necp_policy_mark_all_for_deletion(session);
1094 necp_policy_apply_all(session);
1095 necp_delete_session(session);
1096 return 0;
1097 } else {
1098 return ENOENT;
1099 }
1100 }
1101
1102 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)1103 necp_session_find_from_fd(struct proc *p, int fd,
1104 struct fileproc **fpp, struct necp_session **session)
1105 {
1106 struct fileproc * __single fp = NULL;
1107 int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
1108
1109 if (error == 0) {
1110 *fpp = fp;
1111 *session = (struct necp_session *)fp_get_data(fp);
1112 if ((*session)->necp_fd_type != necp_fd_type_session) {
1113 // Not a client fd, ignore
1114 fp_drop(p, fd, fp, 0);
1115 error = EINVAL;
1116 }
1117 }
1118
1119 return error;
1120 }
1121
1122 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1123 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1124 {
1125 int error = 0;
1126 u_int8_t * __indexable tlv_buffer = NULL;
1127
1128 if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
1129 NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1130 error = EINVAL;
1131 goto done;
1132 }
1133
1134 if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
1135 NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1136 error = EINVAL;
1137 goto done;
1138 }
1139
1140 if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
1141 error = ENOMEM;
1142 goto done;
1143 }
1144
1145 error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
1146 if (error != 0) {
1147 NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1148 goto done;
1149 }
1150
1151 necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1152 if (error != 0) {
1153 NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1154 goto done;
1155 }
1156
1157 error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1158 if (error != 0) {
1159 NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1160 goto done;
1161 }
1162
1163 done:
1164 if (tlv_buffer != NULL) {
1165 kfree_data(tlv_buffer, uap->in_buffer_length);
1166 tlv_buffer = NULL;
1167 }
1168 *retval = error;
1169
1170 return error;
1171 }
1172
1173 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1174 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1175 {
1176 int error = 0;
1177 u_int8_t * __indexable response = NULL;
1178
1179 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1180 NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1181 error = EINVAL;
1182 goto done;
1183 }
1184
1185 necp_policy_id policy_id = 0;
1186 error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1187 if (error != 0) {
1188 NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1189 goto done;
1190 }
1191
1192 struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1193 if (policy == NULL || policy->pending_deletion) {
1194 NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1195 error = ENOENT;
1196 goto done;
1197 }
1198
1199 u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1200 u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1201 u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1202
1203 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1204 NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1205 error = EINVAL;
1206 goto done;
1207 }
1208
1209 if (response_size > NECP_MAX_POLICY_SIZE) {
1210 NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1211 error = EINVAL;
1212 goto done;
1213 }
1214
1215 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1216 if (response == NULL) {
1217 error = ENOMEM;
1218 goto done;
1219 }
1220
1221 u_int8_t *cursor = response;
1222 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1223 if (result_tlv_size) {
1224 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, (void *)&policy->result, response, response_size);
1225 }
1226 if (policy->conditions_size) {
1227 memcpy(response + (cursor - response), policy->conditions, policy->conditions_size);
1228 }
1229
1230 error = copyout(response, uap->out_buffer, response_size);
1231 if (error != 0) {
1232 NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1233 goto done;
1234 }
1235
1236 done:
1237 if (response != NULL) {
1238 kfree_data(response, response_size);
1239 response = NULL;
1240 }
1241 *retval = error;
1242
1243 return error;
1244 }
1245
1246 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1247 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1248 {
1249 int error = 0;
1250
1251 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1252 NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1253 error = EINVAL;
1254 goto done;
1255 }
1256
1257 necp_policy_id delete_policy_id = 0;
1258 error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1259 if (error != 0) {
1260 NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1261 goto done;
1262 }
1263
1264 struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1265 if (policy == NULL || policy->pending_deletion) {
1266 NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1267 error = ENOENT;
1268 goto done;
1269 }
1270
1271 necp_policy_mark_for_deletion(session, policy);
1272 done:
1273 *retval = error;
1274 return error;
1275 }
1276
1277 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1278 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1279 {
1280 #pragma unused(uap)
1281 necp_policy_apply_all(session);
1282 *retval = 0;
1283 return 0;
1284 }
1285
1286 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1287 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1288 {
1289 u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1290 u_int32_t response_size = 0;
1291 u_int8_t * __indexable response = NULL;
1292 int num_policies = 0;
1293 int cur_policy_index = 0;
1294 int error = 0;
1295 struct necp_session_policy *policy;
1296
1297 LIST_FOREACH(policy, &session->policies, chain) {
1298 if (!policy->pending_deletion) {
1299 num_policies++;
1300 }
1301 }
1302
1303 if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1304 NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1305 error = EINVAL;
1306 goto done;
1307 }
1308
1309 response_size = num_policies * tlv_size;
1310 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1311 NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1312 error = EINVAL;
1313 goto done;
1314 }
1315
1316 // Create a response with one Policy ID TLV for each policy
1317 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1318 if (response == NULL) {
1319 error = ENOMEM;
1320 goto done;
1321 }
1322
1323 u_int8_t *cursor = response;
1324 LIST_FOREACH(policy, &session->policies, chain) {
1325 if (!policy->pending_deletion && cur_policy_index < num_policies) {
1326 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1327 cur_policy_index++;
1328 }
1329 }
1330
1331 error = copyout(response, uap->out_buffer, response_size);
1332 if (error != 0) {
1333 NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1334 goto done;
1335 }
1336
1337 done:
1338 if (response != NULL) {
1339 kfree_data(response, response_size);
1340 response = NULL;
1341 }
1342 *retval = error;
1343
1344 return error;
1345 }
1346
1347
1348 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1349 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1350 {
1351 #pragma unused(uap)
1352 necp_policy_mark_all_for_deletion(session);
1353 *retval = 0;
1354 return 0;
1355 }
1356
1357 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1358 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1359 {
1360 int error = 0;
1361 struct necp_session_policy *policy = NULL;
1362 struct necp_session_policy *temp_policy = NULL;
1363
1364 if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1365 NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1366 error = EINVAL;
1367 goto done;
1368 }
1369
1370 necp_session_priority requested_session_priority = 0;
1371 error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1372 if (error != 0) {
1373 NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1374 goto done;
1375 }
1376
1377 // Enforce special session priorities with entitlements
1378 if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1379 requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1380 requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1381 requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1382 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1383 if (cred_result != 0) {
1384 NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1385 error = EPERM;
1386 goto done;
1387 }
1388 }
1389
1390 if (session->session_priority != requested_session_priority) {
1391 session->session_priority = requested_session_priority;
1392 session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1393 session->dirty = TRUE;
1394
1395 // Mark all policies as needing updates
1396 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1397 policy->pending_update = TRUE;
1398 }
1399 }
1400
1401 done:
1402 *retval = error;
1403 return error;
1404 }
1405
1406 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1407 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1408 {
1409 #pragma unused(uap)
1410 session->proc_locked = TRUE;
1411 *retval = 0;
1412 return 0;
1413 }
1414
1415 static int
necp_session_register_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1416 necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1417 {
1418 int error = 0;
1419 struct necp_service_registration *new_service = NULL;
1420
1421 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1422 NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1423 error = EINVAL;
1424 goto done;
1425 }
1426
1427 uuid_t service_uuid;
1428 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1429 if (error != 0) {
1430 NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1431 goto done;
1432 }
1433
1434 new_service = kalloc_type(struct necp_service_registration,
1435 Z_WAITOK | Z_ZERO | Z_NOFAIL);
1436
1437 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1438 new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1439 LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1440 LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1441 lck_rw_done(&necp_kernel_policy_lock);
1442
1443 done:
1444 *retval = error;
1445 return error;
1446 }
1447
1448 static int
necp_session_unregister_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1449 necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1450 {
1451 int error = 0;
1452 struct necp_service_registration * __single service = NULL;
1453 struct necp_service_registration *temp_service = NULL;
1454 struct necp_uuid_id_mapping *mapping = NULL;
1455
1456 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1457 NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1458 error = EINVAL;
1459 goto done;
1460 }
1461
1462 uuid_t service_uuid;
1463 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1464 if (error != 0) {
1465 NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1466 goto done;
1467 }
1468
1469 // Remove all matching services for this session
1470 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1471 mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1472 if (mapping != NULL) {
1473 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1474 if (service->service_id == mapping->id) {
1475 LIST_REMOVE(service, session_chain);
1476 LIST_REMOVE(service, kernel_chain);
1477 kfree_type(struct necp_service_registration, service);
1478 }
1479 }
1480 necp_remove_uuid_service_id_mapping(service_uuid);
1481 }
1482 lck_rw_done(&necp_kernel_policy_lock);
1483
1484 done:
1485 *retval = error;
1486 return error;
1487 }
1488
1489 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1490 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1491 {
1492 #pragma unused(session)
1493 int error = 0;
1494
1495 if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1496 NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1497 error = EINVAL;
1498 goto done;
1499 }
1500
1501 error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1502 done:
1503 *retval = error;
1504 return error;
1505 }
1506
1507 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1508 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1509 {
1510 int error = 0;
1511 struct net_bloom_filter *bloom_filter = NULL;
1512 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1513 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1514
1515 if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1516 in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1517 uap->in_buffer == 0) {
1518 NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1519 error = EINVAL;
1520 goto done;
1521 }
1522
1523 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1524 NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1525 error = EINVAL;
1526 goto done;
1527 }
1528
1529 bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1530 if (bloom_filter == NULL) {
1531 NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1532 error = ENOMEM;
1533 goto done;
1534 }
1535
1536 error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1537 if (error != 0) {
1538 NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1539 goto done;
1540 }
1541
1542 size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1543 if (expected_filter_size != in_buffer_length) {
1544 NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1545 error = EINVAL;
1546 goto done;
1547 }
1548
1549 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1550 u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1551 lck_rw_done(&necp_kernel_policy_lock);
1552
1553 if (filter_id == 0) {
1554 error = ENOMEM;
1555 } else {
1556 // Bloom filter is taken over by the new filter entry, clear the local pointer
1557 bloom_filter = NULL;
1558
1559 error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1560 if (error != 0) {
1561 NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1562 goto done;
1563 }
1564 }
1565
1566 done:
1567 *retval = error;
1568 if (error != 0 && bloom_filter != NULL) {
1569 uint8_t * __single filter_buffer = (uint8_t *)bloom_filter;
1570 kfree_data(filter_buffer, in_buffer_length);
1571 bloom_filter = NULL;
1572 }
1573 return error;
1574 }
1575
1576 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1577 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1578 {
1579 int error = 0;
1580
1581 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1582 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1583 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1584 error = EINVAL;
1585 goto done;
1586 }
1587
1588 u_int32_t filter_id;
1589 error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1590 if (error != 0) {
1591 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1592 goto done;
1593 }
1594
1595 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1596 bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1597 if (!removed) {
1598 error = ENOENT;
1599 }
1600 lck_rw_done(&necp_kernel_policy_lock);
1601
1602 done:
1603 *retval = error;
1604 return error;
1605 }
1606
1607 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1608 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1609 {
1610 #pragma unused(uap)
1611
1612 struct necp_domain_filter * __single filter = NULL;
1613 struct necp_domain_filter *temp_filter = NULL;
1614 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1615 if (os_ref_release_locked(&filter->refcount) == 0) {
1616 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1617 LIST_REMOVE(filter, chain);
1618 lck_rw_done(&necp_kernel_policy_lock);
1619 LIST_REMOVE(filter, owner_chain);
1620 net_bloom_filter_destroy(filter->filter);
1621 kfree_type(struct necp_domain_filter, filter);
1622 }
1623 }
1624
1625 *retval = 0;
1626 return 0;
1627 }
1628
1629 static int
necp_session_add_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1630 necp_session_add_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1631 {
1632 int error = 0;
1633
1634 struct necp_domain_trie_request *domain_trie_request = NULL;
1635 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1636 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1637
1638 if (in_buffer_length < sizeof(struct necp_domain_trie_request) ||
1639 in_buffer_length > NECP_MAX_DOMAIN_TRIE_SIZE ||
1640 uap->in_buffer == 0) {
1641 NECPLOG(LOG_ERR, "necp_session_add_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1642 error = EINVAL;
1643 goto done;
1644 }
1645
1646 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1647 NECPLOG(LOG_ERR, "necp_session_add_domain_trie buffer not large enough (%zu)", (size_t)out_buffer_length);
1648 error = EINVAL;
1649 goto done;
1650 }
1651
1652 domain_trie_request = (struct necp_domain_trie_request *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1653 if (domain_trie_request == NULL) {
1654 NECPLOG(LOG_ERR, "necp_session_add_domain_trie allocate trie request error (%zu)", in_buffer_length);
1655 error = ENOMEM;
1656 goto done;
1657 }
1658
1659 error = copyin(uap->in_buffer, domain_trie_request, in_buffer_length);
1660 if (error != 0) {
1661 NECPLOG(LOG_ERR, "necp_session_add_domain_trie filter copyin error (%d)", error);
1662 goto done;
1663 }
1664
1665 NECPLOG(LOG_INFO, "necp_session_add_domain_trie received %zu bytes <trie mem size %d>", in_buffer_length, domain_trie_request->total_mem_size);
1666
1667 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1668 u_int32_t id = necp_create_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, domain_trie_request, in_buffer_length);
1669 lck_rw_done(&necp_kernel_policy_lock);
1670
1671 if (id == 0) {
1672 error = ENOMEM;
1673 } else {
1674 error = copyout(&id, uap->out_buffer, sizeof(id));
1675 if (error != 0) {
1676 NECPLOG(LOG_ERR, "necp_session_add_domain_trie ID copyout error (%d)", error);
1677 goto done;
1678 }
1679 }
1680
1681 done:
1682 *retval = error;
1683 if (error != 0 && domain_trie_request != NULL) {
1684 uint8_t * __single domain_buffer = (uint8_t *)domain_trie_request;
1685 kfree_data(domain_buffer, in_buffer_length);
1686 domain_trie_request = NULL;
1687 }
1688 return error;
1689 }
1690
1691 static int
necp_session_remove_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1692 necp_session_remove_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1693 {
1694 int error = 0;
1695
1696 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1697 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1698 NECPLOG(LOG_ERR, "necp_session_remove_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1699 error = EINVAL;
1700 goto done;
1701 }
1702
1703 u_int32_t id;
1704 error = copyin(uap->in_buffer, &id, sizeof(id));
1705 if (error != 0) {
1706 NECPLOG(LOG_ERR, "necp_session_remove_domain_trie uuid copyin error (%d)", error);
1707 goto done;
1708 }
1709
1710 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1711 bool removed = necp_remove_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, id);
1712 if (!removed) {
1713 error = ENOENT;
1714 }
1715 lck_rw_done(&necp_kernel_policy_lock);
1716
1717 done:
1718 *retval = error;
1719 return error;
1720 }
1721
1722 static int
necp_session_remove_all_domain_tries(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1723 necp_session_remove_all_domain_tries(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1724 {
1725 #pragma unused(uap)
1726 struct necp_domain_trie* __single trie = NULL;
1727 struct necp_domain_trie* __single temp_trie = NULL;
1728 LIST_FOREACH_SAFE(trie, &session->domain_tries, owner_chain, temp_trie) {
1729 if (os_ref_release_locked(&trie->refcount) == 0) {
1730 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1731 LIST_REMOVE(trie, chain);
1732 lck_rw_done(&necp_kernel_policy_lock);
1733 LIST_REMOVE(trie, owner_chain);
1734 necp_free_domain_trie(trie);
1735 }
1736 }
1737 *retval = 0;
1738 return 0;
1739 }
1740
1741 static int
necp_session_trie_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1742 necp_session_trie_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1743 {
1744 #pragma unused(session)
1745
1746 int error = 0;
1747
1748 uint8_t request_buffer[2000] = { 0 };
1749 uint8_t *ptr = NULL;
1750 uint32_t count = 0;
1751 int output_length = 0;
1752
1753 lck_rw_lock_shared(&necp_kernel_policy_lock);
1754 count = necp_trie_count;
1755 lck_rw_done(&necp_kernel_policy_lock);
1756
1757 if (count == 0) {
1758 error = ENOENT;
1759 goto done;
1760 }
1761
1762 output_length = sizeof(count) + (count * sizeof(struct necp_domain_trie_request)); // first byte contains count
1763 if (output_length > uap->out_buffer_length) {
1764 NECPLOG(LOG_ERR, "necp_session_trie_dump_all out_buffer not large enough for %zu", (size_t)output_length);
1765 error = EINVAL;
1766 goto done;
1767 }
1768 if (output_length > sizeof(request_buffer)) {
1769 NECPLOG(LOG_ERR, "necp_session_trie_dump_all temporary buffer not large enough for %zu", (size_t)output_length);
1770 error = EINVAL;
1771 goto done;
1772 }
1773
1774 memcpy(request_buffer, (u_int8_t *)&count, sizeof(count));
1775 ptr = request_buffer + sizeof(count);
1776
1777 lck_rw_lock_shared(&necp_kernel_policy_lock);
1778 struct necp_domain_trie* __single trie = NULL;
1779 LIST_FOREACH(trie, &necp_global_domain_trie_list, chain) {
1780 if (trie->trie_request != NULL) {
1781 memcpy((u_int8_t *)ptr, (u_int8_t *)trie->trie_request, sizeof(struct necp_domain_trie_request));
1782 ptr += sizeof(struct necp_domain_trie_request);
1783 }
1784 }
1785 lck_rw_done(&necp_kernel_policy_lock);
1786
1787 error = copyout(request_buffer, uap->out_buffer, output_length);
1788
1789 done:
1790 *retval = error;
1791 return error;
1792 }
1793
1794 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1795 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1796 {
1797 struct fileproc * __single fp;
1798 int error = 0;
1799 int return_value = 0;
1800 struct necp_session * __single session = NULL;
1801
1802 error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1803 if (error != 0) {
1804 NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1805 return error;
1806 }
1807
1808 NECP_SESSION_LOCK(session);
1809
1810 if (session->proc_locked) {
1811 // Verify that the calling process is allowed to do actions
1812 uuid_t proc_uuid;
1813 proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1814 if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1815 error = EPERM;
1816 goto done;
1817 }
1818 } else {
1819 // If not locked, update the proc_uuid and proc_pid of the session
1820 proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1821 session->proc_pid = proc_pid(current_proc());
1822 }
1823
1824 u_int32_t action = uap->action;
1825 switch (action) {
1826 case NECP_SESSION_ACTION_POLICY_ADD: {
1827 return_value = necp_session_add_policy(session, uap, retval);
1828 break;
1829 }
1830 case NECP_SESSION_ACTION_POLICY_GET: {
1831 return_value = necp_session_get_policy(session, uap, retval);
1832 break;
1833 }
1834 case NECP_SESSION_ACTION_POLICY_DELETE: {
1835 return_value = necp_session_delete_policy(session, uap, retval);
1836 break;
1837 }
1838 case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1839 return_value = necp_session_apply_all(session, uap, retval);
1840 break;
1841 }
1842 case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1843 return_value = necp_session_list_all(session, uap, retval);
1844 break;
1845 }
1846 case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1847 return_value = necp_session_delete_all(session, uap, retval);
1848 break;
1849 }
1850 case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1851 return_value = necp_session_set_session_priority(session, uap, retval);
1852 break;
1853 }
1854 case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1855 return_value = necp_session_lock_to_process(session, uap, retval);
1856 break;
1857 }
1858 case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1859 return_value = necp_session_register_service(session, uap, retval);
1860 break;
1861 }
1862 case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1863 return_value = necp_session_unregister_service(session, uap, retval);
1864 break;
1865 }
1866 case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1867 return_value = necp_session_dump_all(session, uap, retval);
1868 break;
1869 }
1870 case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1871 return_value = necp_session_add_domain_filter(session, uap, retval);
1872 break;
1873 }
1874 case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1875 return_value = necp_session_remove_domain_filter(session, uap, retval);
1876 break;
1877 }
1878 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1879 return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1880 break;
1881 }
1882 case NECP_SESSION_ACTION_ADD_DOMAIN_TRIE: {
1883 return_value = necp_session_add_domain_trie(session, uap, retval);
1884 break;
1885 }
1886 case NECP_SESSION_ACTION_REMOVE_DOMAIN_TRIE: {
1887 return_value = necp_session_remove_domain_trie(session, uap, retval);
1888 break;
1889 }
1890 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_TRIES: {
1891 return_value = necp_session_remove_all_domain_tries(session, uap, retval);
1892 break;
1893 }
1894 case NECP_SESSION_ACTION_TRIE_DUMP_ALL: {
1895 return_value = necp_session_trie_dump_all(session, uap, retval);
1896 break;
1897 }
1898 default: {
1899 NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1900 return_value = EINVAL;
1901 break;
1902 }
1903 }
1904
1905 done:
1906 NECP_SESSION_UNLOCK(session);
1907 fp_drop(p, uap->necp_fd, fp, 0);
1908 return return_value;
1909 }
1910
1911 struct necp_resolver_key_state {
1912 const struct ccdigest_info *digest_info;
1913 uint8_t key[CCSHA256_OUTPUT_SIZE];
1914 };
1915 static struct necp_resolver_key_state s_necp_resolver_key_state;
1916
1917 static void
necp_generate_resolver_key(void)1918 necp_generate_resolver_key(void)
1919 {
1920 s_necp_resolver_key_state.digest_info = ccsha256_di();
1921 cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1922 }
1923
1924 static void
necp_sign_update_context(const struct ccdigest_info * di,cchmac_ctx_t ctx,uuid_t client_id,u_int32_t sign_type,u_int8_t * data,size_t data_length)1925 necp_sign_update_context(const struct ccdigest_info *di,
1926 cchmac_ctx_t ctx,
1927 uuid_t client_id,
1928 u_int32_t sign_type,
1929 u_int8_t *data,
1930 size_t data_length)
1931 {
1932 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1933 const char * __null_terminated context_string = "NECP Resolver Binder";
1934 uint8_t separator = 0;
1935 cchmac_update(di, ctx, sizeof(context), context);
1936 cchmac_update(di, ctx, strlen(context_string), __unsafe_null_terminated_to_indexable(context_string));
1937 cchmac_update(di, ctx, sizeof(separator), &separator);
1938 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1939 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1940 cchmac_update(di, ctx, data_length, data);
1941 }
1942
1943 int
necp_sign_resolver_answer(uuid_t client_id,u_int32_t sign_type,u_int8_t * data,size_t data_length,u_int8_t * tag,size_t * out_tag_length)1944 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1945 u_int8_t *data, size_t data_length,
1946 u_int8_t *tag, size_t *out_tag_length)
1947 {
1948 if (s_necp_resolver_key_state.digest_info == NULL) {
1949 return EINVAL;
1950 }
1951
1952 if (data == NULL ||
1953 data_length == 0 ||
1954 tag == NULL ||
1955 out_tag_length == NULL) {
1956 return EINVAL;
1957 }
1958
1959 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1960 if (*out_tag_length < required_tag_length) {
1961 return ERANGE;
1962 }
1963
1964 *out_tag_length = required_tag_length;
1965
1966 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1967 s_necp_resolver_key_state.digest_info->block_size, ctx);
1968 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1969 sizeof(s_necp_resolver_key_state.key),
1970 s_necp_resolver_key_state.key);
1971 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1972 ctx, client_id, sign_type, data, data_length);
1973 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1974
1975 return 0;
1976 }
1977
1978 bool
necp_validate_resolver_answer(uuid_t client_id,u_int32_t sign_type,u_int8_t * __sized_by (data_length)data,size_t data_length,u_int8_t * __sized_by (tag_length)tag,size_t tag_length)1979 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1980 u_int8_t * __sized_by(data_length)data, size_t data_length,
1981 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1982 {
1983 if (s_necp_resolver_key_state.digest_info == NULL) {
1984 return false;
1985 }
1986
1987 if (data == NULL ||
1988 data_length == 0 ||
1989 tag == NULL ||
1990 tag_length == 0) {
1991 return false;
1992 }
1993
1994 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1995 if (tag_length != required_tag_length) {
1996 return false;
1997 }
1998
1999 uint8_t actual_tag[required_tag_length];
2000
2001 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
2002 s_necp_resolver_key_state.digest_info->block_size, ctx);
2003 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
2004 sizeof(s_necp_resolver_key_state.key),
2005 s_necp_resolver_key_state.key);
2006 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
2007 ctx, client_id, sign_type, data, data_length);
2008 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
2009
2010 return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
2011 }
2012
2013 struct necp_application_id_key_state {
2014 const struct ccdigest_info *digest_info;
2015 uint8_t key[CCSHA256_OUTPUT_SIZE];
2016 };
2017 static struct necp_application_id_key_state s_necp_application_id_key_state;
2018
2019 static void
necp_generate_application_id_key(void)2020 necp_generate_application_id_key(void)
2021 {
2022 s_necp_application_id_key_state.digest_info = ccsha256_di();
2023 cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
2024 }
2025
2026 static void
necp_sign_application_id_update_context(const struct ccdigest_info * di,cchmac_ctx_t ctx,uuid_t client_id,u_int32_t sign_type)2027 necp_sign_application_id_update_context(const struct ccdigest_info *di,
2028 cchmac_ctx_t ctx,
2029 uuid_t client_id,
2030 u_int32_t sign_type)
2031 {
2032 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
2033 const char context_string[] = "NECP Application ID";
2034 uint8_t separator = 0;
2035 cchmac_update(di, ctx, sizeof(context), context);
2036 cchmac_update(di, ctx, sizeof(context_string) - 1, context_string);
2037 cchmac_update(di, ctx, sizeof(separator), &separator);
2038 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
2039 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
2040 }
2041
2042 int
necp_sign_application_id(uuid_t client_id,u_int32_t sign_type,u_int8_t * __counted_by (* out_tag_length)tag,size_t * out_tag_length)2043 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
2044 u_int8_t *__counted_by(*out_tag_length)tag, size_t *out_tag_length)
2045 {
2046 if (s_necp_application_id_key_state.digest_info == NULL) {
2047 return EINVAL;
2048 }
2049
2050 if (tag == NULL ||
2051 out_tag_length == NULL) {
2052 return EINVAL;
2053 }
2054
2055 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2056 if (*out_tag_length < required_tag_length) {
2057 return ERANGE;
2058 }
2059
2060 *out_tag_length = required_tag_length;
2061
2062 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2063 s_necp_application_id_key_state.digest_info->block_size, ctx);
2064 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2065 sizeof(s_necp_application_id_key_state.key),
2066 s_necp_application_id_key_state.key);
2067 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2068 ctx, client_id, sign_type);
2069 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
2070
2071 return 0;
2072 }
2073
2074 bool
necp_validate_application_id(uuid_t client_id,u_int32_t sign_type,u_int8_t * __sized_by (tag_length)tag,size_t tag_length)2075 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
2076 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
2077 {
2078 if (s_necp_application_id_key_state.digest_info == NULL) {
2079 return false;
2080 }
2081
2082 if (tag == NULL ||
2083 tag_length == 0) {
2084 return false;
2085 }
2086
2087 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2088 if (tag_length != required_tag_length) {
2089 return false;
2090 }
2091
2092 uint8_t actual_tag[required_tag_length];
2093
2094 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2095 s_necp_application_id_key_state.digest_info->block_size, ctx);
2096 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2097 sizeof(s_necp_application_id_key_state.key),
2098 s_necp_application_id_key_state.key);
2099 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2100 ctx, client_id, sign_type);
2101 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
2102
2103 return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
2104 }
2105
2106 void
necp_init(void)2107 necp_init(void)
2108 {
2109 necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
2110 necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
2111
2112 necp_client_init();
2113
2114 TAILQ_INIT(&necp_session_list);
2115
2116 LIST_INIT(&necp_kernel_socket_policies);
2117 LIST_INIT(&necp_kernel_ip_output_policies);
2118
2119 LIST_INIT(&necp_account_id_list);
2120
2121 LIST_INIT(&necp_uuid_service_id_list);
2122
2123 LIST_INIT(&necp_registered_service_list);
2124
2125 LIST_INIT(&necp_route_rules);
2126 LIST_INIT(&necp_aggregate_route_rules);
2127
2128 LIST_INIT(&necp_global_domain_filter_list);
2129 LIST_INIT(&necp_global_domain_trie_list);
2130
2131 necp_generate_resolver_key();
2132 necp_generate_application_id_key();
2133
2134 necp_uuid_app_id_hashtbl = __unsafe_forge_bidi_indexable(struct necp_uuid_id_mapping_head *,
2135 hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask),
2136 NECP_UUID_APP_ID_HASH_SIZE * sizeof(void*));
2137 necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
2138 necp_num_uuid_app_id_mappings = 0;
2139 necp_uuid_app_id_mappings_dirty = FALSE;
2140
2141 necp_kernel_application_policies_condition_mask = 0;
2142 necp_kernel_socket_policies_condition_mask = 0;
2143 necp_kernel_ip_output_policies_condition_mask = 0;
2144
2145 necp_kernel_application_policies_count = 0;
2146 necp_kernel_socket_policies_count = 0;
2147 necp_kernel_socket_policies_non_app_count = 0;
2148 necp_kernel_ip_output_policies_count = 0;
2149 necp_kernel_ip_output_policies_non_id_count = 0;
2150
2151 necp_kernel_socket_policies_gencount = 1;
2152
2153 memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
2154 memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
2155 necp_kernel_socket_policies_app_layer_map = NULL;
2156
2157 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
2158 necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
2159 }
2160
2161 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)2162 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
2163 {
2164 struct kev_msg ev_msg;
2165 memset(&ev_msg, 0, sizeof(ev_msg));
2166
2167 ev_msg.vendor_code = KEV_VENDOR_APPLE;
2168 ev_msg.kev_class = KEV_NETWORK_CLASS;
2169 ev_msg.kev_subclass = KEV_NECP_SUBCLASS;
2170 ev_msg.event_code = KEV_NECP_POLICIES_CHANGED;
2171
2172 ev_msg.dv[0].data_ptr = necp_event_data;
2173 ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
2174 ev_msg.dv[1].data_length = 0;
2175
2176 kev_post_msg(&ev_msg);
2177 }
2178
2179 static inline bool
necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor,u_int8_t type,u_int32_t length,u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length)2180 necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor, u_int8_t type, u_int32_t length,
2181 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2182 {
2183 if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
2184 NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
2185 return false;
2186 }
2187 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2188 if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
2189 (uintptr_t)(next_tlv - buffer) > buffer_length) { // make sure the next TLV has enough room in buffer
2190 NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
2191 length, buffer_length);
2192 return false;
2193 }
2194 return true;
2195 }
2196
2197 u_int8_t * __counted_by(0)
2198 necp_buffer_write_tlv_if_different(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2199 u_int32_t length, const void * __sized_by(length)value, bool *updated,
2200 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2201 {
2202 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2203 u_int8_t * cursor = buffer + (cursor_ - buffer);
2204 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2205 // If we can't fit this TLV, return the current cursor
2206 return cursor;
2207 }
2208 u_int8_t * __indexable next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2209 if (*updated || *(u_int8_t *)(cursor) != type) {
2210 *(u_int8_t *)(cursor) = type;
2211 *updated = TRUE;
2212 }
2213 if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
2214 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2215 *updated = TRUE;
2216 }
2217 if (length > 0) {
2218 if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
2219 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2220 *updated = TRUE;
2221 }
2222 }
2223 return next_tlv;
2224 }
2225
2226 u_int8_t * __counted_by(0)
2227 necp_buffer_write_tlv(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2228 u_int32_t length, const void * __sized_by(length)value,
2229 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2230 {
2231 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2232 u_int8_t * cursor = buffer + (cursor_ - buffer);
2233 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2234 return NULL;
2235 }
2236 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2237 *(u_int8_t *)(cursor) = type;
2238 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2239 if (length > 0) {
2240 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2241 }
2242
2243 return next_tlv;
2244 }
2245
2246 static u_int8_t * __counted_by(0)
2247 necp_buffer_write_tlv_with_flags(u_int8_t * __counted_by(0)cursor_, u_int8_t type, u_int8_t flags,
2248 u_int32_t length, const void * __sized_by(length)value,
2249 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2250 {
2251 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2252 // Add one extra byte to 'length' to account for the flags byte for validation.
2253 u_int8_t * cursor = buffer + (cursor_ - buffer);
2254 if (!necp_buffer_write_tlv_validate(cursor, type, length + 1, buffer, buffer_length)) {
2255 return NULL;
2256 }
2257 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(flags) + sizeof(length) + length);
2258
2259 // TLV with flags format: type, length, flags, value (added 1 byte for the leading flags)
2260 *(u_int8_t *)(cursor) = type;
2261 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2262 *(u_int8_t *)(cursor + sizeof(type) + sizeof(length)) = flags;
2263 if (length > 0) {
2264 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length) + sizeof(flags)), value, length);
2265 }
2266
2267 return next_tlv;
2268 }
2269
2270 u_int8_t
necp_buffer_get_tlv_type(u_int8_t * __counted_by (buffer_length)buffer,size_t buffer_length,u_int32_t tlv_offset)2271 necp_buffer_get_tlv_type(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2272 {
2273 u_int8_t * __indexable type = NULL;
2274 uint64_t end_offset = 0;
2275
2276 if (buffer == NULL ||
2277 os_add_overflow(tlv_offset, sizeof(u_int8_t), &end_offset) || buffer_length < end_offset) {
2278 return 0;
2279 }
2280
2281 type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
2282 return type ? *type : 0;
2283 }
2284
2285 u_int32_t
necp_buffer_get_tlv_length(u_int8_t * __counted_by (buffer_length)buffer,size_t buffer_length,u_int32_t tlv_offset)2286 necp_buffer_get_tlv_length(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2287 {
2288 u_int32_t * __indexable length = NULL;
2289 uint64_t end_offset = 0;
2290
2291 if (buffer == NULL ||
2292 os_add_overflow(tlv_offset, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2293 return 0;
2294 }
2295
2296 length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
2297 return length ? *length : 0;
2298 }
2299
2300 u_int8_t *__sized_by(*value_size)
__necp_buffer_get_tlv_value(u_int8_t * __counted_by (buffer_length)buffer,size_t buffer_length,u_int32_t tlv_offset,u_int32_t * value_size)2301 __necp_buffer_get_tlv_value(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset, u_int32_t * value_size)
2302 {
2303 u_int8_t * __indexable value = NULL;
2304 uint64_t end_offset = 0;
2305
2306 if (buffer == NULL) {
2307 return NULL;
2308 }
2309
2310 u_int32_t length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2311 if (length == 0) {
2312 return NULL;
2313 }
2314
2315 if (os_add3_overflow(tlv_offset, length, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2316 return NULL;
2317 }
2318
2319 if (value_size) {
2320 *value_size = length;
2321 }
2322
2323 value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2324 return value;
2325 }
2326
2327 int
necp_buffer_find_tlv(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)2328 necp_buffer_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2329 {
2330 if (err != NULL) {
2331 *err = ENOENT;
2332 }
2333 if (offset < 0) {
2334 if (err != NULL) {
2335 *err = EINVAL;
2336 }
2337 return -1;
2338 }
2339 int cursor = offset;
2340 int next_cursor;
2341 u_int32_t curr_length;
2342 u_int8_t curr_type;
2343
2344 while (TRUE) {
2345 if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
2346 return -1;
2347 }
2348 if (!next) {
2349 curr_type = necp_buffer_get_tlv_type(buffer, buffer_length, cursor);
2350 } else {
2351 next = 0;
2352 curr_type = NECP_TLV_NIL;
2353 }
2354 curr_length = necp_buffer_get_tlv_length(buffer, buffer_length, cursor);
2355 if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
2356 return -1;
2357 }
2358
2359 next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
2360 if (curr_type == type) {
2361 // check if entire TLV fits inside buffer
2362 if (((u_int32_t)next_cursor) <= buffer_length) {
2363 if (err != NULL) {
2364 *err = 0;
2365 }
2366 return cursor;
2367 } else {
2368 return -1;
2369 }
2370 }
2371 cursor = next_cursor;
2372 }
2373 }
2374
2375 static int
necp_find_tlv(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)2376 necp_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2377 {
2378 int cursor = -1;
2379 if (buffer != NULL) {
2380 cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2381 }
2382 return cursor;
2383 }
2384
2385 static int
necp_get_tlv_at_offset(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int tlv_offset,u_int32_t out_buffer_length,void * __indexable out_buffer,u_int32_t * value_size)2386 necp_get_tlv_at_offset(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2387 int tlv_offset, u_int32_t out_buffer_length, void * __indexable out_buffer, u_int32_t *value_size)
2388 {
2389 if (buffer == NULL) {
2390 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2391 return EINVAL;
2392 }
2393
2394 // Handle buffer parsing
2395
2396 // Validate that buffer has enough room for any TLV
2397 if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2398 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2399 buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2400 return EINVAL;
2401 }
2402
2403 // Validate that buffer has enough room for this TLV
2404 u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2405 if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2406 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2407 tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2408 return EINVAL;
2409 }
2410
2411 if (out_buffer != NULL && out_buffer_length > 0) {
2412 // Validate that out buffer is large enough for value
2413 if (out_buffer_length < tlv_length) {
2414 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2415 out_buffer_length, tlv_length);
2416 return EINVAL;
2417 }
2418
2419 // Get value pointer
2420 u_int8_t * __indexable tlv_value = necp_buffer_get_tlv_value(buffer, buffer_length, tlv_offset, NULL);
2421 if (tlv_value == NULL) {
2422 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2423 return ENOENT;
2424 }
2425
2426 // Copy value
2427 memcpy(out_buffer, tlv_value, tlv_length);
2428 }
2429
2430 // Copy out length
2431 if (value_size != NULL) {
2432 *value_size = tlv_length;
2433 }
2434
2435 return 0;
2436 }
2437
2438 static int
necp_get_tlv(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int offset,u_int8_t type,u_int32_t buff_len,void * __indexable buff,u_int32_t * value_size)2439 necp_get_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2440 int offset, u_int8_t type, u_int32_t buff_len, void * __indexable buff, u_int32_t *value_size)
2441 {
2442 int error = 0;
2443
2444 int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2445 if (tlv_offset < 0) {
2446 return error;
2447 }
2448
2449 return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2450 }
2451
2452 // Session Management
2453
2454 static struct necp_session *
necp_create_session(void)2455 necp_create_session(void)
2456 {
2457 struct necp_session *new_session = NULL;
2458
2459 new_session = kalloc_type(struct necp_session,
2460 Z_WAITOK | Z_ZERO | Z_NOFAIL);
2461
2462 new_session->necp_fd_type = necp_fd_type_session;
2463 new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2464 new_session->dirty = FALSE;
2465 LIST_INIT(&new_session->policies);
2466 LIST_INIT(&new_session->services);
2467 LIST_INIT(&new_session->domain_filters);
2468 LIST_INIT(&new_session->domain_tries);
2469 lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2470
2471 // Take the lock
2472 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2473
2474 // Find the next available control unit
2475 u_int32_t control_unit = 1;
2476 struct necp_session *next_session = NULL;
2477 TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2478 if (next_session->control_unit > control_unit) {
2479 // Found a gap, grab this control unit
2480 break;
2481 }
2482
2483 // Try the next control unit, loop around
2484 control_unit = next_session->control_unit + 1;
2485 }
2486
2487 new_session->control_unit = control_unit;
2488 new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2489
2490 if (next_session != NULL) {
2491 TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2492 } else {
2493 TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2494 }
2495
2496 necp_session_count++;
2497 lck_rw_done(&necp_kernel_policy_lock);
2498
2499 if (necp_debug) {
2500 NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2501 }
2502
2503 return new_session;
2504 }
2505
2506 static void
necp_delete_session(struct necp_session * session)2507 necp_delete_session(struct necp_session *session)
2508 {
2509 if (session != NULL) {
2510 struct necp_service_registration * __single service = NULL;
2511 struct necp_service_registration *temp_service = NULL;
2512 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
2513 LIST_REMOVE(service, session_chain);
2514 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2515 LIST_REMOVE(service, kernel_chain);
2516 lck_rw_done(&necp_kernel_policy_lock);
2517 kfree_type(struct necp_service_registration, service);
2518 }
2519 struct necp_domain_filter * __single filter = NULL;
2520 struct necp_domain_filter *temp_filter = NULL;
2521 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2522 if (os_ref_release_locked(&filter->refcount) == 0) {
2523 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2524 LIST_REMOVE(filter, chain);
2525 lck_rw_done(&necp_kernel_policy_lock);
2526 LIST_REMOVE(filter, owner_chain);
2527 net_bloom_filter_destroy(filter->filter);
2528 kfree_type(struct necp_domain_filter, filter);
2529 }
2530 }
2531 if (necp_debug) {
2532 NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2533 }
2534
2535 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2536 TAILQ_REMOVE(&necp_session_list, session, chain);
2537 necp_session_count--;
2538 lck_rw_done(&necp_kernel_policy_lock);
2539
2540 lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2541 kfree_type(struct necp_session, session);
2542 }
2543 }
2544
2545 // Session Policy Management
2546
2547 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2548 necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2549 {
2550 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2551 }
2552
2553 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2554 necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2555 {
2556 return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2557 }
2558
2559 static inline u_int8_t * __indexable
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2560 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2561 {
2562 return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2563 }
2564
2565 static bool
necp_policy_result_requires_route_rules(u_int8_t * __sized_by (length)buffer,u_int32_t length)2566 necp_policy_result_requires_route_rules(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2567 {
2568 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2569 if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2570 return TRUE;
2571 }
2572 return FALSE;
2573 }
2574
2575 static inline bool
_necp_address_is_valid(struct sockaddr * address)2576 _necp_address_is_valid(struct sockaddr *address)
2577 {
2578 if (address->sa_family == AF_INET) {
2579 return address->sa_len == sizeof(struct sockaddr_in);
2580 } else if (address->sa_family == AF_INET6) {
2581 return address->sa_len == sizeof(struct sockaddr_in6);
2582 } else {
2583 return FALSE;
2584 }
2585 }
2586
2587 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2588
2589 static bool
necp_policy_result_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,bool * is_pass_skip)2590 necp_policy_result_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, bool *is_pass_skip)
2591 {
2592 bool validated = FALSE;
2593 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2594 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2595 *is_pass_skip = FALSE;
2596 switch (type) {
2597 case NECP_POLICY_RESULT_PASS: {
2598 *is_pass_skip = TRUE;
2599 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2600 validated = TRUE;
2601 }
2602 break;
2603 }
2604 case NECP_POLICY_RESULT_DROP: {
2605 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2606 validated = TRUE;
2607 }
2608 break;
2609 }
2610 case NECP_POLICY_RESULT_ROUTE_RULES:
2611 case NECP_POLICY_RESULT_SCOPED_DIRECT:
2612 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2613 validated = TRUE;
2614 break;
2615 }
2616 case NECP_POLICY_RESULT_SKIP:
2617 *is_pass_skip = TRUE;
2618 case NECP_POLICY_RESULT_SOCKET_DIVERT:
2619 case NECP_POLICY_RESULT_SOCKET_FILTER: {
2620 if (parameter_length >= sizeof(u_int32_t)) {
2621 validated = TRUE;
2622 }
2623 break;
2624 }
2625 case NECP_POLICY_RESULT_IP_TUNNEL: {
2626 if (parameter_length > sizeof(u_int32_t)) {
2627 validated = TRUE;
2628 }
2629 break;
2630 }
2631 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2632 if (parameter_length > 0) {
2633 validated = TRUE;
2634 }
2635 break;
2636 }
2637 case NECP_POLICY_RESULT_USE_NETAGENT:
2638 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2639 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2640 if (parameter_length >= sizeof(uuid_t)) {
2641 validated = TRUE;
2642 }
2643 break;
2644 }
2645 default: {
2646 validated = FALSE;
2647 break;
2648 }
2649 }
2650
2651 if (necp_debug) {
2652 NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2653 }
2654
2655 return validated;
2656 }
2657
2658 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2659 necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2660 {
2661 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2662 }
2663
2664 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2665 necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2666 {
2667 return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2668 }
2669
2670 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2671 necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2672 {
2673 return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2674 }
2675
2676 static inline u_int8_t * __indexable
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2677 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2678 {
2679 return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2680 }
2681
2682 static inline bool
necp_policy_condition_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2683 necp_policy_condition_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2684 {
2685 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2686 }
2687
2688 static inline bool
necp_policy_condition_is_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2689 necp_policy_condition_is_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2690 {
2691 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2692 }
2693
2694 static inline bool
necp_policy_condition_is_real_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2695 necp_policy_condition_is_real_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2696 {
2697 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2698 }
2699
2700 static inline bool
necp_policy_condition_requires_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2701 necp_policy_condition_requires_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2702 {
2703 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2704 return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2705 }
2706
2707 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2708 necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2709 {
2710 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2711 u_int32_t condition_length = 0;
2712 pid_t *condition_value = NULL;
2713
2714 if (type == NECP_POLICY_CONDITION_PID) {
2715 condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2716 if (condition_length >= sizeof(pid_t)) {
2717 condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2718 return *condition_value == 0;
2719 }
2720 }
2721 return false;
2722 }
2723
2724 static bool
necp_policy_condition_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,u_int8_t policy_result_type)2725 necp_policy_condition_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, u_int8_t policy_result_type)
2726 {
2727 bool validated = FALSE;
2728 bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2729 policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2730 policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2731 policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2732 policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2733 policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2734 policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2735 policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2736 policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2737 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2738 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2739 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2740 u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2741 switch (type) {
2742 case NECP_POLICY_CONDITION_APPLICATION:
2743 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2744 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2745 condition_length >= sizeof(uuid_t) &&
2746 condition_value != NULL &&
2747 !uuid_is_null(condition_value)) {
2748 validated = TRUE;
2749 }
2750 break;
2751 }
2752 case NECP_POLICY_CONDITION_DOMAIN:
2753 case NECP_POLICY_CONDITION_ACCOUNT:
2754 case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2755 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2756 case NECP_POLICY_CONDITION_URL: {
2757 if (condition_length > 0) {
2758 validated = TRUE;
2759 }
2760 break;
2761 }
2762 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2763 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2764 validated = TRUE;
2765 }
2766 break;
2767 }
2768 case NECP_POLICY_CONDITION_DEFAULT:
2769 case NECP_POLICY_CONDITION_ALL_INTERFACES:
2770 case NECP_POLICY_CONDITION_ENTITLEMENT:
2771 case NECP_POLICY_CONDITION_HAS_CLIENT:
2772 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
2773 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2774 validated = TRUE;
2775 }
2776 break;
2777 }
2778 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2779 if (condition_length == 0 || condition_length >= sizeof(u_int8_t)) {
2780 validated = TRUE;
2781 }
2782 break;
2783 }
2784 case NECP_POLICY_CONDITION_SDK_VERSION: {
2785 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2786 condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2787 validated = TRUE;
2788 }
2789 break;
2790 }
2791 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2792 if (condition_length >= sizeof(u_int16_t)) {
2793 validated = TRUE;
2794 }
2795 break;
2796 }
2797 case NECP_POLICY_CONDITION_PID: {
2798 if (condition_length >= sizeof(pid_t) &&
2799 condition_value != NULL) {
2800 validated = TRUE;
2801 }
2802 break;
2803 }
2804 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2805 if (condition_length >= sizeof(u_int32_t)) {
2806 validated = TRUE;
2807 }
2808 break;
2809 }
2810 case NECP_POLICY_CONDITION_UID:
2811 case NECP_POLICY_CONDITION_REAL_UID: {
2812 if (condition_length >= sizeof(uid_t)) {
2813 validated = TRUE;
2814 }
2815 break;
2816 }
2817 case NECP_POLICY_CONDITION_LOCAL_ADDR:
2818 case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2819 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2820 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2821 validated = TRUE;
2822 }
2823 break;
2824 }
2825 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2826 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2827 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2828 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2829 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2830 validated = TRUE;
2831 }
2832 break;
2833 }
2834 case NECP_POLICY_CONDITION_AGENT_TYPE: {
2835 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2836 condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2837 validated = TRUE;
2838 }
2839 break;
2840 }
2841 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2842 if (condition_length >= sizeof(u_int16_t)) {
2843 validated = TRUE;
2844 }
2845 break;
2846 }
2847 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2848 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2849 if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2850 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2851 validated = TRUE;
2852 }
2853 break;
2854 }
2855 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2856 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2857 if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2858 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2859 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2860 validated = TRUE;
2861 }
2862 break;
2863 }
2864 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2865 if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2866 validated = TRUE;
2867 }
2868 break;
2869 }
2870 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2871 validated = TRUE;
2872 break;
2873 }
2874 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2875 validated = TRUE;
2876 break;
2877 }
2878 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2879 if (condition_length >= sizeof(u_int16_t)) {
2880 u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2881 if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2882 validated = TRUE;
2883 }
2884 }
2885 break;
2886 }
2887 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2888 validated = TRUE;
2889 break;
2890 }
2891 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
2892 validated = TRUE;
2893 break;
2894 }
2895 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2896 validated = TRUE;
2897 break;
2898 }
2899 case NECP_POLICY_CONDITION_SCHEME_PORT: {
2900 if (condition_length >= sizeof(u_int16_t)) {
2901 validated = TRUE;
2902 }
2903 break;
2904 }
2905 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2906 if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2907 validated = TRUE;
2908 }
2909 break;
2910 }
2911 default: {
2912 validated = FALSE;
2913 break;
2914 }
2915 }
2916
2917 if (necp_debug) {
2918 NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2919 }
2920
2921 return validated;
2922 }
2923
2924 static bool
necp_policy_route_rule_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2925 necp_policy_route_rule_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2926 {
2927 return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2928 necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2929 }
2930
2931 static bool
necp_policy_route_rule_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2932 necp_policy_route_rule_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2933 {
2934 bool validated = FALSE;
2935 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2936 switch (type) {
2937 case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2938 validated = TRUE;
2939 break;
2940 }
2941 case NECP_ROUTE_RULE_DENY_INTERFACE: {
2942 validated = TRUE;
2943 break;
2944 }
2945 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2946 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2947 validated = (rule_length >= sizeof(u_int32_t));
2948 break;
2949 }
2950 case NECP_ROUTE_RULE_QOS_MARKING: {
2951 validated = TRUE;
2952 break;
2953 }
2954 case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2955 validated = TRUE;
2956 break;
2957 }
2958 case NECP_ROUTE_RULE_USE_NETAGENT:
2959 case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2960 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2961 validated = (rule_length >= sizeof(uuid_t));
2962 break;
2963 }
2964 case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2965 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2966 validated = (rule_length >= sizeof(uint32_t));
2967 break;
2968 }
2969 default: {
2970 validated = FALSE;
2971 break;
2972 }
2973 }
2974
2975 if (necp_debug) {
2976 NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2977 }
2978
2979 return validated;
2980 }
2981
2982 static int
necp_get_posix_error_for_necp_error(int response_error)2983 necp_get_posix_error_for_necp_error(int response_error)
2984 {
2985 switch (response_error) {
2986 case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2987 case NECP_ERROR_INVALID_TLV:
2988 case NECP_ERROR_POLICY_RESULT_INVALID:
2989 case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2990 case NECP_ERROR_ROUTE_RULES_INVALID: {
2991 return EINVAL;
2992 }
2993 case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2994 return ENOENT;
2995 }
2996 case NECP_ERROR_INVALID_PROCESS: {
2997 return EPERM;
2998 }
2999 case NECP_ERROR_INTERNAL:
3000 default: {
3001 return ENOMEM;
3002 }
3003 }
3004 }
3005
3006 static necp_policy_id
necp_handle_policy_add(struct necp_session * session,u_int8_t * __sized_by (tlv_buffer_length)tlv_buffer,size_t tlv_buffer_length,int offset,int * return_error)3007 necp_handle_policy_add(struct necp_session *session,
3008 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
3009 {
3010 bool has_default_condition = FALSE;
3011 bool has_non_default_condition = FALSE;
3012 bool has_application_condition = FALSE;
3013 bool has_real_application_condition = FALSE;
3014 bool requires_application_condition = FALSE;
3015 bool has_kernel_pid = FALSE;
3016 bool is_pass_skip = FALSE;
3017 u_int32_t conditions_array_size = 0;
3018 u_int8_t *conditions_array = NULL;
3019 int conditions_array_cursor;
3020
3021 bool has_default_route_rule = FALSE;
3022 u_int32_t route_rules_array_size = 0;
3023 u_int8_t *route_rules_array = NULL;
3024 int route_rules_array_cursor;
3025
3026 int cursor;
3027 int error = 0;
3028 u_int32_t response_error = NECP_ERROR_INTERNAL;
3029
3030 necp_policy_order order = 0;
3031 struct necp_session_policy *policy = NULL;
3032 u_int32_t policy_result_size = 0;
3033 u_int8_t *policy_result = NULL;
3034
3035 // Read policy order
3036 error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
3037 if (error) {
3038 NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
3039 response_error = NECP_ERROR_INVALID_TLV;
3040 goto fail;
3041 }
3042
3043 // Read policy result
3044 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
3045 if (error || cursor < 0) {
3046 NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
3047 response_error = NECP_ERROR_INVALID_TLV;
3048 goto fail;
3049 }
3050
3051 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
3052 if (error || policy_result_size == 0) {
3053 NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
3054 response_error = NECP_ERROR_INVALID_TLV;
3055 goto fail;
3056 }
3057 if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
3058 NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
3059 response_error = NECP_ERROR_INVALID_TLV;
3060 goto fail;
3061 }
3062 policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
3063 if (policy_result == NULL) {
3064 NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
3065 response_error = NECP_ERROR_INTERNAL;
3066 goto fail;
3067 }
3068 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
3069 if (error) {
3070 NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
3071 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3072 goto fail;
3073 }
3074 if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
3075 NECPLOG0(LOG_ERR, "Failed to validate policy result");
3076 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3077 goto fail;
3078 }
3079
3080 if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
3081 // Read route rules conditions
3082
3083 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3084 cursor >= 0;
3085 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3086 u_int32_t route_rule_size = 0;
3087 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3088 if (os_add_overflow(route_rules_array_size,
3089 (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
3090 &route_rules_array_size)) {
3091 NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
3092 response_error = NECP_ERROR_INVALID_TLV;
3093 goto fail;
3094 }
3095 }
3096
3097 if (route_rules_array_size == 0) {
3098 NECPLOG0(LOG_ERR, "Failed to get policy route rules");
3099 response_error = NECP_ERROR_INVALID_TLV;
3100 goto fail;
3101 }
3102 if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
3103 NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
3104 response_error = NECP_ERROR_INVALID_TLV;
3105 goto fail;
3106 }
3107 route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
3108 if (route_rules_array == NULL) {
3109 NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
3110 response_error = NECP_ERROR_INTERNAL;
3111 goto fail;
3112 }
3113
3114 route_rules_array_cursor = 0;
3115 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3116 cursor >= 0;
3117 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3118 u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
3119 u_int32_t route_rule_size = 0;
3120 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3121 if (route_rule_size > 0 &&
3122 (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
3123 // Add type
3124 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
3125 route_rules_array_cursor += sizeof(route_rule_type);
3126
3127 // Add length
3128 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
3129 route_rules_array_cursor += sizeof(route_rule_size);
3130
3131 // Add value
3132 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
3133
3134 if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3135 NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
3136 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3137 goto fail;
3138 }
3139
3140 if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3141 if (has_default_route_rule) {
3142 NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
3143 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3144 goto fail;
3145 }
3146 has_default_route_rule = TRUE;
3147 }
3148
3149 route_rules_array_cursor += route_rule_size;
3150 }
3151 }
3152 }
3153
3154 // Read policy conditions
3155 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3156 cursor >= 0;
3157 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3158 u_int32_t condition_size = 0;
3159 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3160
3161 if (condition_size > 0) {
3162 if (os_add_overflow(conditions_array_size,
3163 (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
3164 &conditions_array_size)) {
3165 NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
3166 response_error = NECP_ERROR_INVALID_TLV;
3167 goto fail;
3168 }
3169 }
3170 }
3171
3172 if (conditions_array_size == 0) {
3173 NECPLOG0(LOG_ERR, "Failed to get policy conditions");
3174 response_error = NECP_ERROR_INVALID_TLV;
3175 goto fail;
3176 }
3177 if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
3178 NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
3179 response_error = NECP_ERROR_INVALID_TLV;
3180 goto fail;
3181 }
3182 conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
3183 if (conditions_array == NULL) {
3184 NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
3185 response_error = NECP_ERROR_INTERNAL;
3186 goto fail;
3187 }
3188
3189 conditions_array_cursor = 0;
3190 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3191 cursor >= 0;
3192 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3193 u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
3194 u_int32_t condition_size = 0;
3195 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3196 if (condition_size > 0 &&
3197 (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
3198 // Add type
3199 memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
3200 conditions_array_cursor += sizeof(condition_type);
3201
3202 // Add length
3203 memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
3204 conditions_array_cursor += sizeof(condition_size);
3205
3206 // Add value
3207 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
3208 if (!necp_policy_condition_is_valid((conditions_array + conditions_array_cursor), condition_size, necp_policy_result_get_type_from_buffer(policy_result, policy_result_size))) {
3209 NECPLOG0(LOG_ERR, "Failed to validate policy condition");
3210 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3211 goto fail;
3212 }
3213
3214 if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
3215 has_default_condition = TRUE;
3216 } else {
3217 has_non_default_condition = TRUE;
3218 }
3219 if (has_default_condition && has_non_default_condition) {
3220 NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
3221 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3222 goto fail;
3223 }
3224
3225 if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
3226 has_application_condition = TRUE;
3227 }
3228
3229 if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
3230 has_real_application_condition = TRUE;
3231 }
3232
3233 if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
3234 requires_application_condition = TRUE;
3235 }
3236
3237 if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
3238 has_kernel_pid = TRUE;
3239 }
3240
3241 conditions_array_cursor += condition_size;
3242 }
3243 }
3244
3245 if (requires_application_condition && !has_application_condition) {
3246 NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
3247 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3248 goto fail;
3249 }
3250
3251 if (has_kernel_pid && !is_pass_skip) {
3252 NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
3253 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3254 goto fail;
3255 }
3256
3257 if ((policy = necp_policy_create(session, order, conditions_array, conditions_array_size, route_rules_array, route_rules_array_size, policy_result, policy_result_size)) == NULL) {
3258 response_error = NECP_ERROR_INTERNAL;
3259 goto fail;
3260 }
3261
3262 return policy->local_id;
3263
3264 fail:
3265 if (policy_result != NULL) {
3266 kfree_data_sized_by(policy_result, policy_result_size);
3267 }
3268 if (conditions_array != NULL) {
3269 kfree_data_sized_by(conditions_array, conditions_array_size);
3270 }
3271 if (route_rules_array != NULL) {
3272 kfree_data_sized_by(route_rules_array, route_rules_array_size);
3273 }
3274
3275 if (return_error != NULL) {
3276 *return_error = necp_get_posix_error_for_necp_error(response_error);
3277 }
3278 return 0;
3279 }
3280
3281 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)3282 necp_policy_get_new_id(struct necp_session *session)
3283 {
3284 session->last_policy_id++;
3285 if (session->last_policy_id < 1) {
3286 session->last_policy_id = 1;
3287 }
3288
3289 necp_policy_id newid = session->last_policy_id;
3290
3291 if (newid == 0) {
3292 NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
3293 return 0;
3294 }
3295
3296 return newid;
3297 }
3298
3299 /*
3300 * For the policy dump response this is the structure:
3301 *
3302 * <NECP_PACKET_HEADER>
3303 * {
3304 * type : NECP_TLV_POLICY_DUMP
3305 * length : ...
3306 * value :
3307 * {
3308 * {
3309 * type : NECP_TLV_POLICY_ID
3310 * len : ...
3311 * value : ...
3312 * }
3313 * {
3314 * type : NECP_TLV_POLICY_ORDER
3315 * len : ...
3316 * value : ...
3317 * }
3318 * {
3319 * type : NECP_TLV_POLICY_RESULT_STRING
3320 * len : ...
3321 * value : ...
3322 * }
3323 * {
3324 * type : NECP_TLV_POLICY_OWNER
3325 * len : ...
3326 * value : ...
3327 * }
3328 * {
3329 * type : NECP_TLV_POLICY_CONDITION
3330 * len : ...
3331 * value :
3332 * {
3333 * {
3334 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3335 * len : ...
3336 * value : ...
3337 * }
3338 * {
3339 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3340 * len : ...
3341 * value : ...
3342 * }
3343 * ...
3344 * }
3345 * }
3346 * }
3347 * }
3348 * {
3349 * type : NECP_TLV_POLICY_DUMP
3350 * length : ...
3351 * value :
3352 * {
3353 * {
3354 * type : NECP_TLV_POLICY_ID
3355 * len : ...
3356 * value : ...
3357 * }
3358 * {
3359 * type : NECP_TLV_POLICY_ORDER
3360 * len : ...
3361 * value : ...
3362 * }
3363 * {
3364 * type : NECP_TLV_POLICY_RESULT_STRING
3365 * len : ...
3366 * value : ...
3367 * }
3368 * {
3369 * type : NECP_TLV_POLICY_OWNER
3370 * len : ...
3371 * value : ...
3372 * }
3373 * {
3374 * type : NECP_TLV_POLICY_CONDITION
3375 * len : ...
3376 * value :
3377 * {
3378 * {
3379 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3380 * len : ...
3381 * value : ...
3382 * }
3383 * {
3384 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3385 * len : ...
3386 * value : ...
3387 * }
3388 * ...
3389 * }
3390 * }
3391 * }
3392 * }
3393 * ...
3394 */
3395 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3396 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3397 {
3398 struct necp_kernel_socket_policy * __single policy = NULL;
3399 int policy_i;
3400 int policy_count = 0;
3401 u_int8_t * __indexable * __indexable tlv_buffer_pointers = NULL;
3402 u_int32_t * __indexable tlv_buffer_lengths = NULL;
3403 u_int32_t total_tlv_len = 0;
3404 u_int8_t * __indexable result_buf = NULL;
3405 u_int8_t *result_buf_cursor = result_buf;
3406 char result_string[MAX_RESULT_STRING_LEN];
3407 char proc_name_string[MAXCOMLEN + 1];
3408
3409 int error_code = 0;
3410 bool error_occured = false;
3411 u_int32_t response_error = NECP_ERROR_INTERNAL;
3412
3413 #define REPORT_ERROR(error) error_occured = true; \
3414 response_error = error; \
3415 goto done
3416
3417 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
3418 REPORT_ERROR(error)
3419
3420 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3421 if (cred_result != 0) {
3422 NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3423 REPORT_ERROR(NECP_ERROR_INTERNAL);
3424 }
3425
3426 // LOCK
3427 lck_rw_lock_shared(&necp_kernel_policy_lock);
3428
3429 if (necp_debug) {
3430 NECPLOG0(LOG_DEBUG, "Gathering policies");
3431 }
3432
3433 policy_count = necp_kernel_application_policies_count;
3434
3435 tlv_buffer_pointers = kalloc_type(u_int8_t * __indexable, policy_count, M_WAITOK | Z_ZERO);
3436 if (tlv_buffer_pointers == NULL) {
3437 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3438 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3439 }
3440
3441 tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3442 if (tlv_buffer_lengths == NULL) {
3443 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3444 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3445 }
3446
3447 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3448 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3449
3450 memset(result_string, 0, MAX_RESULT_STRING_LEN);
3451 memset(proc_name_string, 0, MAXCOMLEN + 1);
3452
3453 necp_get_result_description(result_string, policy->result, policy->result_parameter);
3454 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3455
3456 u_int16_t proc_name_len = strbuflen(proc_name_string, sizeof(proc_name_string) - 1) + 1;
3457 u_int16_t result_string_len = strbuflen(result_string, sizeof(result_string) - 1) + 1;
3458
3459 if (necp_debug) {
3460 NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3461 }
3462
3463 u_int32_t total_allocated_bytes = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) + // NECP_TLV_POLICY_ID
3464 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) + // NECP_TLV_POLICY_ORDER
3465 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) + // NECP_TLV_POLICY_SESSION_ORDER
3466 sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len + // NECP_TLV_POLICY_RESULT_STRING
3467 sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len + // NECP_TLV_POLICY_OWNER
3468 sizeof(u_int8_t) + sizeof(u_int32_t); // NECP_TLV_POLICY_CONDITION
3469
3470 // We now traverse the condition_mask to see how much space we need to allocate
3471 u_int64_t condition_mask = policy->condition_mask;
3472 u_int64_t condition_negated_mask = policy->condition_negated_mask;
3473 u_int8_t num_conditions = 0;
3474 struct necp_string_id_mapping *account_id_entry = NULL;
3475 char if_name[IFXNAMSIZ];
3476 u_int32_t condition_tlv_length = 0;
3477 memset(if_name, 0, sizeof(if_name));
3478
3479 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3480 num_conditions++;
3481 } else {
3482 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3483 num_conditions++;
3484 }
3485 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3486 num_conditions++;
3487 }
3488 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3489 snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3490 condition_tlv_length += strbuflen(if_name, sizeof(if_name) - 1) + 1;
3491 num_conditions++;
3492 }
3493 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3494 condition_tlv_length += sizeof(policy->cond_protocol);
3495 num_conditions++;
3496 }
3497 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3498 condition_tlv_length += sizeof(uuid_t);
3499 num_conditions++;
3500 }
3501 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3502 condition_tlv_length += sizeof(uuid_t);
3503 num_conditions++;
3504 }
3505 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3506 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3507 u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3508 condition_tlv_length += domain_len;
3509 num_conditions++;
3510 }
3511 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3512 condition_tlv_length += sizeof(u_int32_t);
3513 num_conditions++;
3514 }
3515 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3516 u_int32_t url_len = strlen(policy->cond_url) + 1;
3517 condition_tlv_length += url_len;
3518 num_conditions++;
3519 }
3520 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3521 account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3522 u_int32_t account_id_len = 0;
3523 if (account_id_entry) {
3524 account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3525 }
3526 condition_tlv_length += account_id_len;
3527 num_conditions++;
3528 }
3529 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3530 condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3531 num_conditions++;
3532 }
3533 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3534 condition_tlv_length += sizeof(uid_t);
3535 num_conditions++;
3536 }
3537 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3538 condition_tlv_length += sizeof(uid_t);
3539 num_conditions++;
3540 }
3541 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3542 condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3543 num_conditions++;
3544 }
3545 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3546 num_conditions++;
3547 }
3548 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3549 u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3550 condition_tlv_length += entitlement_len;
3551 num_conditions++;
3552 }
3553 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3554 num_conditions++;
3555 }
3556 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3557 num_conditions++;
3558 }
3559 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3560 condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3561 num_conditions++;
3562 }
3563 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3564 condition_tlv_length += sizeof(policy->cond_local_networks_flags);
3565 num_conditions++;
3566 }
3567 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3568 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3569 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3570 } else {
3571 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3572 }
3573 num_conditions++;
3574 }
3575 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3576 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3577 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3578 } else {
3579 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3580 }
3581 num_conditions++;
3582 }
3583 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3584 condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3585 num_conditions++;
3586 }
3587 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3588 condition_tlv_length += sizeof(u_int32_t);
3589 num_conditions++;
3590 }
3591 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3592 num_conditions++;
3593 }
3594 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3595 num_conditions++;
3596 }
3597 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3598 u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3599 condition_tlv_length += identifier_len;
3600 num_conditions++;
3601 }
3602 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3603 condition_tlv_length += sizeof(u_int16_t);
3604 num_conditions++;
3605 }
3606 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3607 num_conditions++;
3608 }
3609 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3610 num_conditions++;
3611 }
3612 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3613 condition_tlv_length += sizeof(u_int16_t);
3614 num_conditions++;
3615 }
3616 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3617 condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3618 num_conditions++;
3619 }
3620 }
3621
3622 // These are for the condition TLVs (id, length, flags). The space for "value" is already accounted for above.
3623 condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int8_t));
3624 total_allocated_bytes += condition_tlv_length;
3625
3626 u_int8_t * __indexable tlv_buffer;
3627 tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3628 if (tlv_buffer == NULL) {
3629 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3630 continue;
3631 }
3632
3633 u_int8_t *cursor = tlv_buffer;
3634 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3635 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3636 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3637 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3638 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3639
3640 #define N_QUICK 256
3641 u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3642
3643 u_int8_t * __indexable cond_buf; // To be used for condition TLVs
3644 if (condition_tlv_length <= N_QUICK) {
3645 cond_buf = q_cond_buf;
3646 } else {
3647 cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3648 if (cond_buf == NULL) {
3649 NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3650 kfree_data(tlv_buffer, total_allocated_bytes);
3651 continue;
3652 }
3653 }
3654
3655 memset(cond_buf, 0, condition_tlv_length);
3656 u_int8_t *cond_buf_cursor = cond_buf;
3657 u_int8_t cond_flags = 0;
3658 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3659 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3660 } else {
3661 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3662 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3663 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ALL_INTERFACES, cond_flags, 0, "", cond_buf, condition_tlv_length);
3664 }
3665 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3666 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3667 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_HAS_CLIENT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3668 }
3669 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3670 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3671 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_NETWORKS, cond_flags, sizeof(policy->cond_local_networks_flags), &policy->cond_local_networks_flags, cond_buf, condition_tlv_length);
3672 }
3673 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3674 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3675 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE, cond_flags, strbuflen(if_name, sizeof(if_name) - 1) + 1,
3676 if_name, cond_buf, condition_tlv_length);
3677 }
3678 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3679 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3680 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_IP_PROTOCOL, cond_flags, sizeof(policy->cond_protocol), &policy->cond_protocol,
3681 cond_buf, condition_tlv_length);
3682 }
3683 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3684 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3685 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3686 if (entry != NULL) {
3687 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3688 cond_buf, condition_tlv_length);
3689 }
3690 }
3691 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3692 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3693 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3694 if (entry != NULL) {
3695 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3696 cond_buf, condition_tlv_length);
3697 }
3698 }
3699 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3700 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3701 cond_flags = ((condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) || (condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3702 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN, cond_flags, strlen(policy->cond_domain) + 1, __unsafe_null_terminated_to_indexable(policy->cond_domain), cond_buf, condition_tlv_length);
3703 }
3704 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3705 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3706 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN_FILTER, cond_flags, sizeof(policy->cond_domain_filter), &policy->cond_domain_filter,
3707 cond_buf, condition_tlv_length);
3708 }
3709 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3710 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_URL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3711 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_URL, cond_flags, strlen(policy->cond_url) + 1, __unsafe_null_terminated_to_indexable(policy->cond_url), cond_buf, condition_tlv_length);
3712 }
3713 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3714 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3715 if (account_id_entry != NULL) {
3716 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ACCOUNT, cond_flags, strlen(account_id_entry->string) + 1, __unsafe_null_terminated_to_indexable(account_id_entry->string), cond_buf, condition_tlv_length);
3717 }
3718 }
3719 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3720 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3721 uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3722 memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3723 memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3724 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PID, cond_flags, sizeof(pid_buffer), &pid_buffer,
3725 cond_buf, condition_tlv_length);
3726 }
3727 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3728 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3729 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_UID, cond_flags, sizeof(policy->cond_uid), &policy->cond_uid,
3730 cond_buf, condition_tlv_length);
3731 }
3732 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3733 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3734 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_UID, cond_flags, sizeof(policy->cond_real_uid), &policy->cond_real_uid,
3735 cond_buf, condition_tlv_length);
3736 }
3737 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3738 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3739 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_TRAFFIC_CLASS, cond_flags, sizeof(policy->cond_traffic_class), &policy->cond_traffic_class,
3740 cond_buf, condition_tlv_length);
3741 }
3742 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3743 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3744 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, 0, "",
3745 cond_buf, condition_tlv_length);
3746 }
3747 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3748 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3749 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, strlen(policy->cond_custom_entitlement) + 1, __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement), cond_buf, condition_tlv_length);
3750 }
3751 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3752 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3753 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PLATFORM_BINARY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3754 }
3755 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3756 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3757 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3758 }
3759 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3760 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SDK_VERSION) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3761 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION, cond_flags,
3762 sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3763 cond_buf, condition_tlv_length);
3764 }
3765 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3766 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3767 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3768 struct necp_policy_condition_addr_range range;
3769 memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3770 memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3771 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, cond_flags, sizeof(range), &range,
3772 cond_buf, condition_tlv_length);
3773 } else {
3774 struct necp_policy_condition_addr addr;
3775 addr.prefix = policy->cond_local_prefix;
3776 memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3777 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, cond_flags, sizeof(addr), &addr,
3778 cond_buf, condition_tlv_length);
3779 }
3780 }
3781 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3782 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3783 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3784 struct necp_policy_condition_addr_range range;
3785 memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3786 memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3787 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, cond_flags, sizeof(range), &range,
3788 cond_buf, condition_tlv_length);
3789 } else {
3790 struct necp_policy_condition_addr addr;
3791 addr.prefix = policy->cond_remote_prefix;
3792 memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3793 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, cond_flags, sizeof(addr), &addr,
3794 cond_buf, condition_tlv_length);
3795 }
3796 }
3797 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3798 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3799 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE, cond_flags,
3800 sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3801 cond_buf, condition_tlv_length);
3802 }
3803 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3804 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3805 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_CLIENT_FLAGS, cond_flags, sizeof(policy->cond_client_flags), &policy->cond_client_flags, cond_buf, condition_tlv_length);
3806 }
3807 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3808 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3809 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3810 }
3811 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3812 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3813 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3814 }
3815 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3816 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3817 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SIGNING_IDENTIFIER, cond_flags, strlen(policy->cond_signing_identifier) + 1, __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier), cond_buf, condition_tlv_length);
3818 }
3819 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3820 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3821 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PACKET_FILTER_TAGS, cond_flags, sizeof(policy->cond_packet_filter_tags), &policy->cond_packet_filter_tags, cond_buf, condition_tlv_length);
3822 }
3823 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3824 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3825 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK, cond_flags, 0, "", cond_buf, condition_tlv_length);
3826 }
3827 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3828 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3829 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3830 }
3831 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3832 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3833 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SCHEME_PORT, cond_flags, sizeof(policy->cond_scheme_port), &policy->cond_scheme_port, cond_buf, condition_tlv_length);
3834 }
3835 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3836 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3837 uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3838 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3839 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3840 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3841 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, cond_flags, sizeof(flags), &flags,
3842 cond_buf, condition_tlv_length);
3843 }
3844 }
3845
3846 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3847 if (cond_buf != q_cond_buf) {
3848 kfree_data(cond_buf, condition_tlv_length);
3849 }
3850
3851 tlv_buffer_pointers[policy_i] = tlv_buffer;
3852 tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3853
3854 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
3855 total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3856 }
3857
3858 // UNLOCK
3859 lck_rw_done(&necp_kernel_policy_lock);
3860
3861 // Copy out
3862 if (out_buffer != 0) {
3863 if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3864 NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3865 REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3866 }
3867
3868 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3869 result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3870 if (result_buf == NULL) {
3871 NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3872 REPORT_ERROR(NECP_ERROR_INTERNAL);
3873 }
3874
3875 // Add four bytes for total length at the start
3876 memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3877
3878 // Copy the TLVs
3879 result_buf_cursor = result_buf + sizeof(u_int32_t);
3880 for (int i = 0; i < policy_count; i++) {
3881 if (tlv_buffer_pointers[i] != NULL) {
3882 result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3883 result_buf, total_tlv_len + sizeof(u_int32_t));
3884 }
3885 }
3886
3887 int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3888 if (copy_error) {
3889 NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3890 REPORT_ERROR(NECP_ERROR_INTERNAL);
3891 }
3892 }
3893
3894 done:
3895
3896 if (error_occured) {
3897 error_code = necp_get_posix_error_for_necp_error(response_error);
3898 }
3899
3900 if (result_buf != NULL) {
3901 kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3902 }
3903
3904 if (tlv_buffer_pointers != NULL) {
3905 for (int i = 0; i < policy_count; i++) {
3906 if (tlv_buffer_pointers[i] != NULL) {
3907 kfree_data_addr(tlv_buffer_pointers[i]);
3908 tlv_buffer_pointers[i] = NULL;
3909 }
3910 }
3911 kfree_type(u_int8_t * __indexable, policy_count, tlv_buffer_pointers);
3912 }
3913
3914 if (tlv_buffer_lengths != NULL) {
3915 kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3916 }
3917 #undef N_QUICK
3918 #undef RESET_COND_BUF
3919 #undef REPORT_ERROR
3920 #undef UNLOCK_AND_REPORT_ERROR
3921
3922 return error_code;
3923 }
3924
3925 static struct necp_session_policy *
necp_policy_create(struct necp_session * session,necp_policy_order order,u_int8_t * __sized_by (conditions_array_size)conditions_array,u_int32_t conditions_array_size,u_int8_t * __sized_by (route_rules_array_size)route_rules_array,u_int32_t route_rules_array_size,u_int8_t * __sized_by (result_size)result,u_int32_t result_size)3926 necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t * __sized_by(conditions_array_size)conditions_array, u_int32_t conditions_array_size, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, u_int8_t *__sized_by(result_size)result, u_int32_t result_size)
3927 {
3928 struct necp_session_policy *new_policy = NULL;
3929 struct necp_session_policy *tmp_policy = NULL;
3930
3931 if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3932 goto done;
3933 }
3934
3935 new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3936 new_policy->applied = FALSE;
3937 new_policy->pending_deletion = FALSE;
3938 new_policy->pending_update = FALSE;
3939 new_policy->order = order;
3940 new_policy->conditions = conditions_array;
3941 new_policy->conditions_size = conditions_array_size;
3942 new_policy->route_rules = route_rules_array;
3943 new_policy->route_rules_size = route_rules_array_size;
3944 new_policy->result = result;
3945 new_policy->result_size = result_size;
3946 new_policy->local_id = necp_policy_get_new_id(session);
3947
3948 LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3949
3950 session->dirty = TRUE;
3951
3952 if (necp_debug) {
3953 NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3954 }
3955 done:
3956 return new_policy;
3957 }
3958
3959 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3960 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3961 {
3962 struct necp_session_policy *policy = NULL;
3963 if (policy_id == 0) {
3964 return NULL;
3965 }
3966
3967 LIST_FOREACH(policy, &session->policies, chain) {
3968 if (policy->local_id == policy_id) {
3969 return policy;
3970 }
3971 }
3972
3973 return NULL;
3974 }
3975
3976 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3977 necp_policy_get_result_type(struct necp_session_policy *policy)
3978 {
3979 return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3980 }
3981
3982 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3983 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3984 {
3985 return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3986 }
3987
3988 static bool
necp_policy_get_result_parameter(struct necp_session_policy * policy,u_int8_t * __sized_by (parameter_buffer_length)parameter_buffer,u_int32_t parameter_buffer_length)3989 necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t * __sized_by(parameter_buffer_length)parameter_buffer, u_int32_t parameter_buffer_length)
3990 {
3991 if (policy) {
3992 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3993 if (parameter_buffer_length >= parameter_length) {
3994 u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3995 if (parameter && parameter_buffer) {
3996 memcpy(parameter_buffer, parameter, parameter_length);
3997 return TRUE;
3998 }
3999 }
4000 }
4001
4002 return FALSE;
4003 }
4004
4005 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)4006 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
4007 {
4008 if (session == NULL || policy == NULL) {
4009 return FALSE;
4010 }
4011
4012 policy->pending_deletion = TRUE;
4013 session->dirty = TRUE;
4014
4015 if (necp_debug) {
4016 NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
4017 }
4018 return TRUE;
4019 }
4020
4021 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)4022 necp_policy_mark_all_for_deletion(struct necp_session *session)
4023 {
4024 struct necp_session_policy *policy = NULL;
4025 struct necp_session_policy *temp_policy = NULL;
4026
4027 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4028 necp_policy_mark_for_deletion(session, policy);
4029 }
4030
4031 return TRUE;
4032 }
4033
4034 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)4035 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
4036 {
4037 if (session == NULL || policy == NULL) {
4038 return FALSE;
4039 }
4040
4041 LIST_REMOVE(policy, chain);
4042
4043 if (policy->result) {
4044 kfree_data_sized_by(policy->result, policy->result_size);
4045 policy->result = NULL;
4046 policy->result_size = 0;
4047 }
4048
4049 if (policy->conditions) {
4050 kfree_data_sized_by(policy->conditions, policy->conditions_size);
4051 policy->conditions = NULL;
4052 policy->conditions_size = 0;
4053 }
4054
4055 if (policy->route_rules) {
4056 kfree_data_sized_by(policy->route_rules, policy->route_rules_size);
4057 policy->route_rules = NULL;
4058 policy->route_rules_size = 0;
4059 }
4060
4061 zfree(necp_session_policy_zone, policy);
4062
4063 if (necp_debug) {
4064 NECPLOG0(LOG_DEBUG, "Removed NECP policy");
4065 }
4066 return TRUE;
4067 }
4068
4069 static bool
necp_policy_unapply(struct necp_session_policy * policy)4070 necp_policy_unapply(struct necp_session_policy *policy)
4071 {
4072 int i = 0;
4073 if (policy == NULL) {
4074 return FALSE;
4075 }
4076
4077 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4078
4079 // Release local uuid mappings
4080 if (!uuid_is_null(policy->applied_app_uuid)) {
4081 bool removed_mapping = FALSE;
4082 if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
4083 necp_uuid_app_id_mappings_dirty = TRUE;
4084 necp_num_uuid_app_id_mappings--;
4085 }
4086 uuid_clear(policy->applied_app_uuid);
4087 }
4088 if (!uuid_is_null(policy->applied_real_app_uuid)) {
4089 necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
4090 uuid_clear(policy->applied_real_app_uuid);
4091 }
4092 if (!uuid_is_null(policy->applied_result_uuid)) {
4093 necp_remove_uuid_service_id_mapping(policy->applied_result_uuid);
4094 uuid_clear(policy->applied_result_uuid);
4095 }
4096
4097 // Release string mappings
4098 if (policy->applied_account != NULL) {
4099 necp_remove_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(policy->applied_account));
4100 kfree_data_sized_by(policy->applied_account, policy->applied_account_size);
4101 policy->applied_account = NULL;
4102 policy->applied_account_size = 0;
4103 }
4104
4105 // Release route rule
4106 if (policy->applied_route_rules_id != 0) {
4107 necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
4108 policy->applied_route_rules_id = 0;
4109 }
4110
4111 // Remove socket policies
4112 for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
4113 if (policy->kernel_socket_policies[i] != 0) {
4114 necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
4115 policy->kernel_socket_policies[i] = 0;
4116 }
4117 }
4118
4119 // Remove IP output policies
4120 for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
4121 if (policy->kernel_ip_output_policies[i] != 0) {
4122 necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
4123 policy->kernel_ip_output_policies[i] = 0;
4124 }
4125 }
4126
4127 policy->applied = FALSE;
4128
4129 return TRUE;
4130 }
4131
4132 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
4133 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
4134 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
4135 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
4136 struct necp_policy_result_ip_tunnel {
4137 u_int32_t secondary_result;
4138 char interface_name[IFXNAMSIZ];
4139 } __attribute__((__packed__));
4140
4141 struct necp_policy_result_service {
4142 uuid_t identifier;
4143 u_int32_t data;
4144 } __attribute__((__packed__));
4145
4146 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy)4147 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
4148 {
4149 bool socket_only_conditions = FALSE;
4150 bool socket_ip_conditions = FALSE;
4151
4152 bool socket_layer_non_id_conditions = FALSE;
4153 bool ip_output_layer_non_id_conditions = FALSE;
4154 bool ip_output_layer_non_id_only = FALSE;
4155 bool ip_output_layer_id_condition = FALSE;
4156 bool ip_output_layer_tunnel_condition_from_id = FALSE;
4157 bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
4158 necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
4159
4160 u_int64_t master_condition_mask = 0;
4161 u_int64_t master_condition_negated_mask = 0;
4162 ifnet_t __single cond_bound_interface = NULL;
4163 u_int32_t cond_account_id = 0;
4164 char *cond_domain __null_terminated = NULL;
4165 u_int32_t cond_domain_filter = 0;
4166 char *cond_url __null_terminated = NULL;
4167 char *cond_custom_entitlement __null_terminated = NULL;
4168 char *cond_signing_identifier __null_terminated = NULL;
4169 pid_t cond_pid = 0;
4170 int32_t cond_pid_version = 0;
4171 uid_t cond_uid = 0;
4172 uid_t cond_real_uid = 0;
4173 necp_app_id cond_app_id = 0;
4174 necp_app_id cond_real_app_id = 0;
4175 struct necp_policy_condition_tc_range cond_traffic_class;
4176 cond_traffic_class.start_tc = 0;
4177 cond_traffic_class.end_tc = 0;
4178 u_int16_t cond_protocol = 0;
4179 union necp_sockaddr_union cond_local_start;
4180 union necp_sockaddr_union cond_local_end;
4181 u_int8_t cond_local_prefix = 0;
4182 union necp_sockaddr_union cond_remote_start;
4183 union necp_sockaddr_union cond_remote_end;
4184 u_int8_t cond_remote_prefix = 0;
4185 u_int32_t cond_client_flags = 0;
4186 u_int8_t cond_local_networks_flags = 0;
4187 u_int32_t offset = 0;
4188 u_int8_t ultimate_result = 0;
4189 u_int32_t secondary_result = 0;
4190 struct necp_policy_condition_agent_type cond_agent_type = {};
4191 struct necp_policy_condition_sdk_version cond_sdk_version = {};
4192 u_int16_t cond_packet_filter_tags = 0;
4193 u_int16_t cond_scheme_port = 0;
4194 u_int32_t cond_bound_interface_flags = 0;
4195 u_int32_t cond_bound_interface_eflags = 0;
4196 u_int32_t cond_bound_interface_xflags = 0;
4197 necp_kernel_policy_result_parameter secondary_result_parameter;
4198 memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
4199 u_int32_t cond_last_interface_index = 0;
4200 necp_kernel_policy_result_parameter ultimate_result_parameter;
4201 memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
4202
4203 if (policy == NULL) {
4204 return FALSE;
4205 }
4206
4207 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4208
4209 // Process conditions
4210 while (offset < policy->conditions_size) {
4211 u_int32_t length = 0;
4212 u_int8_t * __indexable value = necp_buffer_get_tlv_value(policy->conditions, policy->conditions_size, offset, &length);
4213
4214 u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
4215 u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
4216 bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
4217 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
4218 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
4219 switch (condition_type) {
4220 case NECP_POLICY_CONDITION_DEFAULT: {
4221 socket_ip_conditions = TRUE;
4222 break;
4223 }
4224 case NECP_POLICY_CONDITION_ALL_INTERFACES: {
4225 master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
4226 socket_ip_conditions = TRUE;
4227 break;
4228 }
4229 case NECP_POLICY_CONDITION_HAS_CLIENT: {
4230 master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
4231 socket_only_conditions = TRUE;
4232 break;
4233 }
4234 case NECP_POLICY_CONDITION_ENTITLEMENT: {
4235 if (condition_length > 0) {
4236 if (cond_custom_entitlement == NULL) {
4237 cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
4238 if (cond_custom_entitlement != NULL) {
4239 master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
4240 socket_only_conditions = TRUE;
4241 }
4242 }
4243 } else {
4244 master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
4245 socket_only_conditions = TRUE;
4246 }
4247 break;
4248 }
4249 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
4250 master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4251 if (condition_is_negative) {
4252 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4253 }
4254 socket_only_conditions = TRUE;
4255 break;
4256 }
4257 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
4258 master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
4259 socket_only_conditions = TRUE;
4260 break;
4261 }
4262 case NECP_POLICY_CONDITION_SDK_VERSION: {
4263 if (condition_length >= sizeof(cond_sdk_version)) {
4264 master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
4265 memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
4266 socket_only_conditions = TRUE;
4267 }
4268 break;
4269 }
4270 case NECP_POLICY_CONDITION_DOMAIN: {
4271 // Make sure there is only one such rule
4272 if (condition_length > 0 && cond_domain == NULL) {
4273 const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
4274
4275 u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
4276 cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
4277 if (cond_domain != NULL) {
4278 master_condition_mask |= mask_value;
4279 if (condition_is_negative) {
4280 master_condition_negated_mask |= mask_value;
4281 }
4282 socket_only_conditions = TRUE;
4283 }
4284 }
4285 break;
4286 }
4287 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
4288 // Make sure there is only one such rule
4289 if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
4290 memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
4291 if (cond_domain_filter != 0) {
4292 master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4293 if (condition_is_negative) {
4294 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4295 }
4296 socket_only_conditions = TRUE;
4297 }
4298 }
4299 break;
4300 }
4301 case NECP_POLICY_CONDITION_URL: {
4302 // Make sure there is only one such rule
4303 if (condition_length > 0 && cond_url == NULL) {
4304 u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
4305 cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
4306 if (cond_url != NULL) {
4307 master_condition_mask |= mask_value;
4308 if (condition_is_negative) {
4309 master_condition_negated_mask |= mask_value;
4310 }
4311 socket_only_conditions = TRUE;
4312 }
4313 }
4314 break;
4315 }
4316 case NECP_POLICY_CONDITION_ACCOUNT: {
4317 // Make sure there is only one such rule
4318 if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
4319 size_t string_buffer_size = 0;
4320 char * __sized_by(string_buffer_size) string = NULL;
4321 string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
4322 string_buffer_size = condition_length + 1;
4323 if (string != NULL) {
4324 memcpy(string, condition_value, condition_length);
4325 string[condition_length] = 0;
4326 cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(string, &string[condition_length]));
4327 if (cond_account_id != 0) {
4328 policy->applied_account = string; // Save the string in parent policy
4329 policy->applied_account_size = string_buffer_size;
4330 master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4331 if (condition_is_negative) {
4332 master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4333 }
4334 socket_only_conditions = TRUE;
4335 } else {
4336 kfree_data_sized_by(string, string_buffer_size);
4337 }
4338 }
4339 }
4340 break;
4341 }
4342 case NECP_POLICY_CONDITION_APPLICATION: {
4343 // Make sure there is only one such rule, because we save the uuid in the policy
4344 if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
4345 bool allocated_mapping = FALSE;
4346 uuid_t application_uuid;
4347 memcpy(application_uuid, condition_value, sizeof(uuid_t));
4348 cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
4349 if (cond_app_id != 0) {
4350 if (allocated_mapping) {
4351 necp_uuid_app_id_mappings_dirty = TRUE;
4352 necp_num_uuid_app_id_mappings++;
4353 }
4354 uuid_copy(policy->applied_app_uuid, application_uuid);
4355 master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
4356 if (condition_is_negative) {
4357 master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
4358 }
4359 socket_only_conditions = TRUE;
4360 }
4361 }
4362 break;
4363 }
4364 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
4365 // Make sure there is only one such rule, because we save the uuid in the policy
4366 if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
4367 uuid_t real_application_uuid;
4368 memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
4369 cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
4370 if (cond_real_app_id != 0) {
4371 uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
4372 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4373 if (condition_is_negative) {
4374 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4375 }
4376 socket_only_conditions = TRUE;
4377 }
4378 }
4379 break;
4380 }
4381 case NECP_POLICY_CONDITION_PID: {
4382 if (condition_length >= sizeof(pid_t)) {
4383 master_condition_mask |= NECP_KERNEL_CONDITION_PID;
4384 if (condition_is_negative) {
4385 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
4386 }
4387 memcpy(&cond_pid, condition_value, sizeof(cond_pid));
4388 if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
4389 memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
4390 }
4391 socket_only_conditions = TRUE;
4392 }
4393 break;
4394 }
4395 case NECP_POLICY_CONDITION_UID: {
4396 if (condition_length >= sizeof(uid_t)) {
4397 master_condition_mask |= NECP_KERNEL_CONDITION_UID;
4398 if (condition_is_negative) {
4399 master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
4400 }
4401 memcpy(&cond_uid, condition_value, sizeof(cond_uid));
4402 socket_only_conditions = TRUE;
4403 }
4404 break;
4405 }
4406 case NECP_POLICY_CONDITION_REAL_UID: {
4407 if (condition_length >= sizeof(uid_t)) {
4408 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4409 if (condition_is_negative) {
4410 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4411 }
4412 memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
4413 socket_only_conditions = TRUE;
4414 }
4415 break;
4416 }
4417 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
4418 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
4419 master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4420 if (condition_is_negative) {
4421 master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4422 }
4423 memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
4424 socket_only_conditions = TRUE;
4425 }
4426 break;
4427 }
4428 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4429 if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4430 char interface_name[IFXNAMSIZ];
4431 memcpy(interface_name, condition_value, condition_length);
4432 interface_name[condition_length - 1] = 0; // Make sure the string is NULL terminated
4433 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[condition_length - 1]), &cond_bound_interface) == 0) {
4434 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4435 if (condition_is_negative) {
4436 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4437 }
4438 }
4439 socket_ip_conditions = TRUE;
4440 }
4441 break;
4442 }
4443 case NECP_POLICY_CONDITION_IP_PROTOCOL:
4444 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4445 if (condition_length >= sizeof(u_int16_t)) {
4446 master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4447 if (condition_is_negative) {
4448 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4449 }
4450 memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4451 if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4452 socket_only_conditions = TRUE;
4453 } else {
4454 socket_ip_conditions = TRUE;
4455 }
4456 }
4457 break;
4458 }
4459 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4460 if (condition_is_negative) {
4461 master_condition_negated_mask |= NECP_POLICY_CONDITION_LOCAL_NETWORKS;
4462 }
4463 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4464 socket_ip_conditions = TRUE;
4465 if (condition_length >= sizeof(u_int8_t)) {
4466 memcpy(&cond_local_networks_flags, condition_value, sizeof(cond_local_networks_flags));
4467 }
4468 break;
4469 }
4470 case NECP_POLICY_CONDITION_LOCAL_ADDR:
4471 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4472 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4473 if (!necp_address_is_valid(&address_struct->address.sa)) {
4474 break;
4475 }
4476
4477 cond_local_prefix = address_struct->prefix;
4478 memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4479 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4480 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4481 if (condition_is_negative) {
4482 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4483 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4484 }
4485 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4486 socket_only_conditions = TRUE;
4487 } else {
4488 socket_ip_conditions = TRUE;
4489 }
4490 break;
4491 }
4492 case NECP_POLICY_CONDITION_REMOTE_ADDR:
4493 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4494 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4495 if (!necp_address_is_valid(&address_struct->address.sa)) {
4496 break;
4497 }
4498
4499 cond_remote_prefix = address_struct->prefix;
4500 memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4501 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4502 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4503 if (condition_is_negative) {
4504 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4505 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4506 }
4507 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4508 socket_only_conditions = TRUE;
4509 } else {
4510 socket_ip_conditions = TRUE;
4511 }
4512 break;
4513 }
4514 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4515 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4516 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4517 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4518 !necp_address_is_valid(&address_struct->end_address.sa)) {
4519 break;
4520 }
4521
4522 memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4523 memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4524 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4525 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4526 if (condition_is_negative) {
4527 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4528 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4529 }
4530 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4531 socket_only_conditions = TRUE;
4532 } else {
4533 socket_ip_conditions = TRUE;
4534 }
4535 break;
4536 }
4537 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4538 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4539 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4540 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4541 !necp_address_is_valid(&address_struct->end_address.sa)) {
4542 break;
4543 }
4544
4545 memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4546 memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4547 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4548 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4549 if (condition_is_negative) {
4550 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4551 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4552 }
4553 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4554 socket_only_conditions = TRUE;
4555 } else {
4556 socket_ip_conditions = TRUE;
4557 }
4558 break;
4559 }
4560 case NECP_POLICY_CONDITION_AGENT_TYPE: {
4561 if (condition_length >= sizeof(cond_agent_type)) {
4562 master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4563 memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4564 socket_only_conditions = TRUE;
4565 }
4566 break;
4567 }
4568 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4569 if (condition_is_negative) {
4570 master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4571 }
4572 master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4573 socket_only_conditions = TRUE;
4574 if (condition_length >= sizeof(u_int32_t)) {
4575 memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4576 } else {
4577 // Empty means match on fallback traffic
4578 cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4579 }
4580 break;
4581 }
4582 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4583 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4584 if (condition_is_negative) {
4585 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4586 }
4587 socket_only_conditions = TRUE;
4588 break;
4589 }
4590 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4591 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4592 if (condition_is_negative) {
4593 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4594 }
4595 socket_only_conditions = TRUE;
4596 break;
4597 }
4598 case NECP_POLICY_CONDITION_SCHEME_PORT: {
4599 master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4600 if (condition_is_negative) {
4601 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4602 }
4603 memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4604 socket_ip_conditions = TRUE;
4605 break;
4606 }
4607 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4608 if (condition_length > 0) {
4609 if (cond_signing_identifier == NULL) {
4610 cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4611 if (cond_signing_identifier != NULL) {
4612 master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4613 socket_only_conditions = TRUE;
4614 if (condition_is_negative) {
4615 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4616 }
4617 }
4618 }
4619 }
4620 break;
4621 }
4622 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4623 if (condition_length >= sizeof(u_int16_t)) {
4624 master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4625 if (condition_is_negative) {
4626 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4627 }
4628 memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4629 socket_ip_conditions = TRUE;
4630 }
4631 break;
4632 }
4633 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4634 master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4635 if (condition_is_negative) {
4636 master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4637 }
4638 socket_only_conditions = TRUE;
4639 break;
4640 }
4641 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4642 master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4643 if (condition_is_negative) {
4644 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4645 }
4646 socket_only_conditions = TRUE;
4647 break;
4648 }
4649 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4650 if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4651 u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4652 memcpy(&flags, condition_value, sizeof(flags));
4653 cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4654 cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4655 cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4656 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4657 if (condition_is_negative) {
4658 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4659 }
4660 socket_ip_conditions = TRUE;
4661 }
4662 break;
4663 }
4664 default: {
4665 break;
4666 }
4667 }
4668
4669 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4670 }
4671
4672 // Process result
4673 ultimate_result = necp_policy_get_result_type(policy);
4674 switch (ultimate_result) {
4675 case NECP_POLICY_RESULT_PASS: {
4676 u_int32_t pass_flags = 0;
4677 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4678 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4679 ultimate_result_parameter.pass_flags = pass_flags;
4680 }
4681 }
4682 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4683 socket_layer_non_id_conditions = TRUE;
4684 ip_output_layer_id_condition = TRUE;
4685 } else if (socket_ip_conditions) {
4686 socket_layer_non_id_conditions = TRUE;
4687 ip_output_layer_id_condition = TRUE;
4688 ip_output_layer_non_id_conditions = TRUE;
4689 }
4690 break;
4691 }
4692 case NECP_POLICY_RESULT_DROP: {
4693 u_int32_t drop_flags = 0;
4694 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4695 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4696 ultimate_result_parameter.drop_flags = drop_flags;
4697 }
4698 }
4699 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4700 socket_layer_non_id_conditions = TRUE;
4701 } else if (socket_ip_conditions) {
4702 socket_layer_non_id_conditions = TRUE;
4703 ip_output_layer_non_id_conditions = TRUE;
4704 ip_output_layer_non_id_only = TRUE; // Only apply drop to packets that didn't go through socket layer
4705 }
4706 break;
4707 }
4708 case NECP_POLICY_RESULT_SKIP: {
4709 u_int32_t skip_policy_order = 0;
4710 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4711 ultimate_result_parameter.skip_policy_order = skip_policy_order;
4712 }
4713
4714 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4715 socket_layer_non_id_conditions = TRUE;
4716 ip_output_layer_id_condition = TRUE;
4717 } else if (socket_ip_conditions) {
4718 socket_layer_non_id_conditions = TRUE;
4719 ip_output_layer_non_id_conditions = TRUE;
4720 }
4721 break;
4722 }
4723 case NECP_POLICY_RESULT_SOCKET_DIVERT:
4724 case NECP_POLICY_RESULT_SOCKET_FILTER: {
4725 u_int32_t control_unit = 0;
4726 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4727 ultimate_result_parameter.flow_divert_control_unit = control_unit;
4728 }
4729 socket_layer_non_id_conditions = TRUE;
4730 break;
4731 }
4732 case NECP_POLICY_RESULT_IP_TUNNEL: {
4733 struct necp_policy_result_ip_tunnel tunnel_parameters;
4734 u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4735 if (tunnel_parameters_length > sizeof(u_int32_t) &&
4736 tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4737 necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4738 ifnet_t __single tunnel_interface = NULL;
4739 tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0; // Make sure the string is NULL terminated
4740 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4741 ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4742 ifnet_release(tunnel_interface);
4743 }
4744
4745 secondary_result = tunnel_parameters.secondary_result;
4746 if (secondary_result) {
4747 cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4748 }
4749 }
4750
4751 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4752 socket_layer_non_id_conditions = TRUE;
4753 ip_output_layer_id_condition = TRUE;
4754 if (secondary_result) {
4755 ip_output_layer_tunnel_condition_from_id = TRUE;
4756 }
4757 } else if (socket_ip_conditions) {
4758 socket_layer_non_id_conditions = TRUE;
4759 ip_output_layer_id_condition = TRUE;
4760 ip_output_layer_non_id_conditions = TRUE;
4761 if (secondary_result) {
4762 ip_output_layer_tunnel_condition_from_id = TRUE;
4763 ip_output_layer_tunnel_condition_from_non_id = TRUE;
4764 }
4765 }
4766 break;
4767 }
4768 case NECP_POLICY_RESULT_USE_NETAGENT:
4769 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4770 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4771 uuid_t netagent_uuid;
4772 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4773 ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
4774 if (ultimate_result_parameter.netagent_id != 0) {
4775 uuid_copy(policy->applied_result_uuid, netagent_uuid);
4776 socket_layer_non_id_conditions = TRUE;
4777 }
4778 }
4779 break;
4780 }
4781 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4782 u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4783 if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4784 char interface_name[IFXNAMSIZ];
4785 ifnet_t __single scope_interface = NULL;
4786 necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4787 interface_name[interface_name_length - 1] = 0; // Make sure the string is NULL terminated
4788 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4789 ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4790 socket_layer_non_id_conditions = TRUE;
4791 ifnet_release(scope_interface);
4792 }
4793 }
4794 break;
4795 }
4796 case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4797 socket_layer_non_id_conditions = TRUE;
4798 break;
4799 }
4800 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4801 socket_layer_non_id_conditions = TRUE;
4802 break;
4803 }
4804 case NECP_POLICY_RESULT_ROUTE_RULES: {
4805 if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4806 bool has_socket_only_actions = FALSE;
4807 u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4808 if (route_rule_id > 0) {
4809 policy->applied_route_rules_id = route_rule_id;
4810 ultimate_result_parameter.route_rule_id = route_rule_id;
4811 if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4812 socket_layer_non_id_conditions = TRUE;
4813 } else if (socket_ip_conditions) {
4814 socket_layer_non_id_conditions = TRUE;
4815 ip_output_layer_non_id_conditions = TRUE;
4816 ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4817 }
4818 }
4819 }
4820 break;
4821 }
4822 default: {
4823 break;
4824 }
4825 }
4826
4827 if (socket_layer_non_id_conditions) {
4828 necp_kernel_policy_id policy_id = necp_kernel_socket_policy_add(policy->order, session->session_order, session->proc_pid, master_condition_mask, master_condition_negated_mask, cond_app_id, cond_real_app_id, cond_custom_entitlement, cond_account_id, cond_domain, cond_domain_filter, cond_url, cond_pid, cond_pid_version, cond_uid, cond_real_uid, cond_bound_interface, cond_traffic_class, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, &cond_agent_type, &cond_sdk_version, cond_client_flags, cond_signing_identifier, cond_packet_filter_tags, cond_scheme_port, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, ultimate_result, ultimate_result_parameter);
4829
4830 if (policy_id == 0) {
4831 NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4832 goto fail;
4833 }
4834
4835 cond_ip_output_layer_id = policy_id;
4836 policy->kernel_socket_policies[0] = policy_id;
4837 }
4838
4839 if (ip_output_layer_non_id_conditions) {
4840 u_int64_t condition_mask = master_condition_mask;
4841 if (ip_output_layer_non_id_only) {
4842 condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4843 }
4844
4845 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS, session->session_order, session->proc_pid, condition_mask, master_condition_negated_mask, NECP_KERNEL_POLICY_ID_NONE, cond_bound_interface, 0, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, cond_packet_filter_tags, cond_scheme_port, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, ultimate_result, ultimate_result_parameter);
4846
4847 if (policy_id == 0) {
4848 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4849 goto fail;
4850 }
4851
4852 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4853 }
4854
4855 if (ip_output_layer_id_condition) {
4856 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION, session->session_order, session->proc_pid, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_ALL_INTERFACES, 0, cond_ip_output_layer_id, NULL, 0, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, ultimate_result, ultimate_result_parameter);
4857
4858 if (policy_id == 0) {
4859 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4860 goto fail;
4861 }
4862
4863 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4864 }
4865
4866 // Extra policies for IP Output tunnels for when packets loop back
4867 if (ip_output_layer_tunnel_condition_from_id) {
4868 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION, session->session_order, session->proc_pid, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_ALL_INTERFACES, 0, policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS], NULL, cond_last_interface_index, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, secondary_result, secondary_result_parameter);
4869
4870 if (policy_id == 0) {
4871 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4872 goto fail;
4873 }
4874
4875 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4876 }
4877
4878 if (ip_output_layer_tunnel_condition_from_id) {
4879 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION, session->session_order, session->proc_pid, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_ALL_INTERFACES, 0, policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION], NULL, cond_last_interface_index, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, secondary_result, secondary_result_parameter);
4880
4881 if (policy_id == 0) {
4882 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4883 goto fail;
4884 }
4885
4886 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4887 }
4888
4889 policy->applied = TRUE;
4890 policy->pending_update = FALSE;
4891 return TRUE;
4892
4893 fail:
4894 return FALSE;
4895 }
4896
4897 static void
necp_policy_apply_all(struct necp_session * session)4898 necp_policy_apply_all(struct necp_session *session)
4899 {
4900 struct necp_session_policy *policy = NULL;
4901 struct necp_session_policy *temp_policy = NULL;
4902 struct kev_necp_policies_changed_data kev_data;
4903 kev_data.changed_count = 0;
4904
4905 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4906
4907 // Remove exisiting applied policies
4908 if (session->dirty) {
4909 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4910 if (policy->pending_deletion) {
4911 if (policy->applied) {
4912 necp_policy_unapply(policy);
4913 }
4914 // Delete the policy
4915 necp_policy_delete(session, policy);
4916 } else if (!policy->applied) {
4917 necp_policy_apply(session, policy);
4918 } else if (policy->pending_update) {
4919 // Must have been applied, but needs an update. Remove and re-add.
4920 necp_policy_unapply(policy);
4921 necp_policy_apply(session, policy);
4922 }
4923 }
4924
4925 necp_kernel_socket_policies_update_uuid_table();
4926 necp_kernel_socket_policies_reprocess();
4927 necp_kernel_ip_output_policies_reprocess();
4928
4929 // Clear dirty bit flags
4930 session->dirty = FALSE;
4931 }
4932
4933 lck_rw_done(&necp_kernel_policy_lock);
4934
4935 necp_update_all_clients();
4936 necp_post_change_event(&kev_data);
4937
4938 if (necp_debug) {
4939 NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4940 }
4941 }
4942
4943 // Kernel Policy Management
4944 // ---------------------
4945 // Kernel policies are derived from session policies
4946 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4947 necp_kernel_policy_get_new_id(bool socket_level)
4948 {
4949 static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4950 static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4951
4952 necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4953
4954 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4955
4956 if (socket_level) {
4957 bool wrapped = FALSE;
4958 do {
4959 necp_last_kernel_socket_policy_id++;
4960 if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4961 necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4962 if (wrapped) {
4963 // Already wrapped, give up
4964 NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4965 return NECP_KERNEL_POLICY_ID_NONE;
4966 }
4967 necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4968 wrapped = TRUE;
4969 }
4970 newid = necp_last_kernel_socket_policy_id;
4971 } while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4972 } else {
4973 bool wrapped = FALSE;
4974 do {
4975 necp_last_kernel_ip_policy_id++;
4976 if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4977 if (wrapped) {
4978 // Already wrapped, give up
4979 NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4980 return NECP_KERNEL_POLICY_ID_NONE;
4981 }
4982 necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4983 wrapped = TRUE;
4984 }
4985 newid = necp_last_kernel_ip_policy_id;
4986 } while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4987 }
4988
4989 if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4990 NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4991 return NECP_KERNEL_POLICY_ID_NONE;
4992 }
4993
4994 return newid;
4995 }
4996
4997 #define NECP_KERNEL_VALID_SOCKET_CONDITIONS (NECP_KERNEL_CONDITION_APP_ID | NECP_KERNEL_CONDITION_REAL_APP_ID | NECP_KERNEL_CONDITION_DOMAIN | NECP_KERNEL_CONDITION_ACCOUNT_ID | NECP_KERNEL_CONDITION_PID | NECP_KERNEL_CONDITION_UID | NECP_KERNEL_CONDITION_REAL_UID | NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_TRAFFIC_CLASS | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_ENTITLEMENT | NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT | NECP_KERNEL_CONDITION_AGENT_TYPE | NECP_KERNEL_CONDITION_HAS_CLIENT | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_CLIENT_FLAGS | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_PLATFORM_BINARY | NECP_KERNEL_CONDITION_SDK_VERSION | NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER | NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS | NECP_KERNEL_CONDITION_IS_LOOPBACK | NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY | NECP_KERNEL_CONDITION_SCHEME_PORT | NECP_KERNEL_CONDITION_DOMAIN_FILTER | NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT | NECP_KERNEL_CONDITION_EXACT_DOMAIN | NECP_KERNEL_CONDITION_URL | NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)
4998
4999 static necp_kernel_policy_id
necp_kernel_socket_policy_add(necp_policy_order order,u_int32_t session_order,int session_pid,u_int64_t condition_mask,u_int64_t condition_negated_mask,necp_app_id cond_app_id,necp_app_id cond_real_app_id,char * cond_custom_entitlement __null_terminated,u_int32_t cond_account_id,char * cond_domain __null_terminated,u_int32_t cond_domain_filter,char * cond_url __null_terminated,pid_t cond_pid,int32_t cond_pid_version,uid_t cond_uid,uid_t cond_real_uid,ifnet_t cond_bound_interface,struct necp_policy_condition_tc_range cond_traffic_class,u_int16_t cond_protocol,union necp_sockaddr_union * __single cond_local_start,union necp_sockaddr_union * cond_local_end,u_int8_t cond_local_prefix,union necp_sockaddr_union * cond_remote_start,union necp_sockaddr_union * cond_remote_end,u_int8_t cond_remote_prefix,struct necp_policy_condition_agent_type * cond_agent_type,struct necp_policy_condition_sdk_version * cond_sdk_version,u_int32_t cond_client_flags,char * cond_signing_identifier __null_terminated,u_int16_t cond_packet_filter_tags,u_int16_t cond_scheme_port,u_int32_t cond_bound_interface_flags,u_int32_t cond_bound_interface_eflags,u_int32_t cond_bound_interface_xflags,u_int8_t cond_local_networks_flags,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)5000 necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement __null_terminated, u_int32_t cond_account_id, char *cond_domain __null_terminated, u_int32_t cond_domain_filter, char *cond_url __null_terminated, pid_t cond_pid, int32_t cond_pid_version, uid_t cond_uid, uid_t cond_real_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union * __single cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier __null_terminated, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
5001 {
5002 struct necp_kernel_socket_policy *new_kernel_policy = NULL;
5003 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5004
5005 new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
5006
5007 new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
5008 new_kernel_policy->order = order;
5009 new_kernel_policy->session_order = session_order;
5010 new_kernel_policy->session_pid = session_pid;
5011
5012 // Sanitize condition mask
5013 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
5014 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
5015 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
5016 }
5017 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
5018 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
5019 }
5020 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
5021 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
5022 }
5023 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
5024 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
5025 }
5026 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
5027 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
5028 }
5029 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
5030 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
5031 }
5032 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
5033 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
5034 }
5035 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
5036
5037 // Set condition values
5038 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
5039 new_kernel_policy->cond_app_id = cond_app_id;
5040 }
5041 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
5042 new_kernel_policy->cond_real_app_id = cond_real_app_id;
5043 }
5044 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
5045 new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
5046 }
5047 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
5048 new_kernel_policy->cond_account_id = cond_account_id;
5049 }
5050 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
5051 (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
5052 new_kernel_policy->cond_domain = cond_domain;
5053 new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
5054 }
5055 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
5056 new_kernel_policy->cond_domain_filter = cond_domain_filter;
5057 }
5058 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
5059 new_kernel_policy->cond_url = cond_url;
5060 }
5061 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
5062 new_kernel_policy->cond_pid = cond_pid;
5063 new_kernel_policy->cond_pid_version = cond_pid_version;
5064 }
5065 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
5066 new_kernel_policy->cond_uid = cond_uid;
5067 }
5068 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
5069 new_kernel_policy->cond_real_uid = cond_real_uid;
5070 }
5071 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
5072 if (cond_bound_interface) {
5073 ifnet_reference(cond_bound_interface);
5074 }
5075 new_kernel_policy->cond_bound_interface = cond_bound_interface;
5076 }
5077 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
5078 new_kernel_policy->cond_traffic_class = cond_traffic_class;
5079 }
5080 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
5081 new_kernel_policy->cond_protocol = cond_protocol;
5082 }
5083 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5084 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
5085 }
5086 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5087 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
5088 }
5089 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5090 new_kernel_policy->cond_local_prefix = cond_local_prefix;
5091 }
5092 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5093 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
5094 }
5095 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5096 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
5097 }
5098 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5099 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
5100 }
5101 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
5102 memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
5103 }
5104 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
5105 memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
5106 }
5107 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
5108 new_kernel_policy->cond_client_flags = cond_client_flags;
5109 }
5110 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
5111 new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
5112 }
5113 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
5114 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
5115 }
5116 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
5117 new_kernel_policy->cond_scheme_port = cond_scheme_port;
5118 }
5119 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
5120 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
5121 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
5122 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
5123 }
5124 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
5125 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
5126 }
5127
5128 new_kernel_policy->result = result;
5129 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
5130
5131 if (necp_debug) {
5132 NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
5133 }
5134 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
5135
5136 return new_kernel_policy ? new_kernel_policy->id : 0;
5137 }
5138
5139 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)5140 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
5141 {
5142 struct necp_kernel_socket_policy *kernel_policy = NULL;
5143 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5144
5145 if (policy_id == 0) {
5146 return NULL;
5147 }
5148
5149 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
5150 if (kernel_policy->id == policy_id) {
5151 return kernel_policy;
5152 }
5153 }
5154
5155 return NULL;
5156 }
5157
5158 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)5159 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
5160 {
5161 struct necp_kernel_socket_policy * __single policy = NULL;
5162 char * __indexable buffer = NULL;
5163 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5164
5165 policy = necp_kernel_socket_policy_find(policy_id);
5166 if (policy) {
5167 LIST_REMOVE(policy, chain);
5168
5169 if (policy->cond_bound_interface) {
5170 ifnet_release(policy->cond_bound_interface);
5171 policy->cond_bound_interface = NULL;
5172 }
5173
5174 if (policy->cond_domain) {
5175 buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
5176 kfree_data_addr(buffer);
5177 policy->cond_domain = NULL;
5178 }
5179
5180 if (policy->cond_url) {
5181 buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
5182 kfree_data_addr(buffer);
5183 policy->cond_url = NULL;
5184 }
5185
5186 if (policy->cond_custom_entitlement) {
5187 buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
5188 kfree_data_addr(buffer);
5189 policy->cond_custom_entitlement = NULL;
5190 }
5191
5192 if (policy->cond_signing_identifier) {
5193 buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
5194 kfree_data_addr(buffer);
5195 policy->cond_signing_identifier = NULL;
5196 }
5197
5198 zfree(necp_socket_policy_zone, policy);
5199 return TRUE;
5200 }
5201
5202 return FALSE;
5203 }
5204
5205 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)5206 __sized_by(MAX_RESULT_STRING_LEN)
5207 necp_get_result_description(char * __sized_by(MAX_RESULT_STRING_LEN) result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
5208 {
5209 uuid_string_t uuid_string;
5210 switch (result) {
5211 case NECP_KERNEL_POLICY_RESULT_NONE: {
5212 snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
5213 break;
5214 }
5215 case NECP_KERNEL_POLICY_RESULT_PASS: {
5216 snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
5217 break;
5218 }
5219 case NECP_KERNEL_POLICY_RESULT_SKIP: {
5220 snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
5221 break;
5222 }
5223 case NECP_KERNEL_POLICY_RESULT_DROP: {
5224 snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5225 break;
5226 }
5227 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5228 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5229 break;
5230 }
5231 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5232 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5233 break;
5234 }
5235 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5236 ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5237 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5238 break;
5239 }
5240 case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5241 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5242 break;
5243 }
5244 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5245 ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5246 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5247 break;
5248 }
5249 case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5250 snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5251 break;
5252 }
5253 case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5254 snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5255 break;
5256 }
5257 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5258 int index = 0;
5259 char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5260 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5261 if (route_rule != NULL) {
5262 for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5263 if (route_rule->exception_if_indices[index] != 0) {
5264 ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5265 snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5266 } else {
5267 memset(interface_names[index], 0, IFXNAMSIZ);
5268 }
5269 }
5270 switch (route_rule->default_action) {
5271 case NECP_ROUTE_RULE_DENY_INTERFACE:
5272 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5273 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Only %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
5274 (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5275 (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5276 (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5277 (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5278 (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5279 (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5280 (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5281 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5282 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5283 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5284 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5285 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5286 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5287 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5288 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5289 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5290 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5291 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5292 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5293 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5294 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5295 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5296 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5297 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5298 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5299 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5300 break;
5301 case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5302 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
5303 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5304 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5305 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5306 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5307 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5308 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5309 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5310 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5311 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5312 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5313 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5314 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5315 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5316 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5317 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5318 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5319 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5320 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5321 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5322 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5323 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5324 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5325 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5326 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5327 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5328 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5329 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5330 break;
5331 case NECP_ROUTE_RULE_QOS_MARKING:
5332 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (QoSMarking %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
5333 (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5334 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5335 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5336 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5337 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5338 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5339 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5340 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5341 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5342 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5343 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5344 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5345 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5346 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5347 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5348 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5349 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5350 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5351 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5352 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5353 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5354 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5355 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5356 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5357 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5358 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5359 break;
5360 default:
5361 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5362 break;
5363 }
5364 }
5365 break;
5366 }
5367 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5368 bool found_mapping = FALSE;
5369 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5370 if (mapping != NULL) {
5371 uuid_unparse(mapping->uuid, uuid_string);
5372 found_mapping = TRUE;
5373 }
5374 snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5375 break;
5376 }
5377 case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5378 bool found_mapping = FALSE;
5379 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5380 if (mapping != NULL) {
5381 uuid_unparse(mapping->uuid, uuid_string);
5382 found_mapping = TRUE;
5383 }
5384 snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5385 break;
5386 }
5387 case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5388 bool found_mapping = FALSE;
5389 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5390 if (mapping != NULL) {
5391 uuid_unparse(mapping->uuid, uuid_string);
5392 found_mapping = TRUE;
5393 }
5394 snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5395 break;
5396 }
5397 default: {
5398 snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5399 break;
5400 }
5401 }
5402 return result_string;
5403 }
5404
5405 static void
necp_kernel_socket_policies_dump_all(void)5406 necp_kernel_socket_policies_dump_all(void)
5407 {
5408 if (necp_debug) {
5409 struct necp_kernel_socket_policy *policy = NULL;
5410 int policy_i;
5411 int app_i;
5412 char result_string[MAX_RESULT_STRING_LEN];
5413 char proc_name_string[MAXCOMLEN + 1];
5414 memset(result_string, 0, MAX_RESULT_STRING_LEN);
5415 memset(proc_name_string, 0, MAXCOMLEN + 1);
5416
5417 NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5418 NECPLOG0(LOG_DEBUG, "-----------\n");
5419 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5420 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5421 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5422 NECPLOG(LOG_DEBUG, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d\tMask: %llx\tResult: %s\n", policy_i, policy->id, proc_name_string, policy->session_order, policy->order, policy->condition_mask, necp_get_result_description(result_string, policy->result, policy->result_parameter));
5423 }
5424 if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5425 NECPLOG0(LOG_DEBUG, "-----------\n");
5426 }
5427
5428 NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5429 NECPLOG0(LOG_DEBUG, "-----------\n");
5430 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5431 NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5432 for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5433 policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5434 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5435 NECPLOG(LOG_DEBUG, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d\tMask: %llx\tResult: %s\n", policy_i, policy->id, proc_name_string, policy->session_order, policy->order, policy->condition_mask, necp_get_result_description(result_string, policy->result, policy->result_parameter));
5436 }
5437 NECPLOG0(LOG_DEBUG, "-----------\n");
5438 }
5439 }
5440 }
5441
5442 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5443 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5444 {
5445 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5446 // Drop always cancels out lower policies
5447 return TRUE;
5448 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5449 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5450 upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5451 upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5452 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5453 upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
5454 // Filters and route rules never cancel out lower policies
5455 return FALSE;
5456 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5457 if (upper_policy->session_order != lower_policy->session_order) {
5458 // A skip cannot override a policy of a different session
5459 return FALSE;
5460 } else {
5461 if (upper_policy->result_parameter.skip_policy_order == 0 ||
5462 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5463 // This policy is beyond the skip
5464 return FALSE;
5465 } else {
5466 // This policy is inside the skip
5467 return TRUE;
5468 }
5469 }
5470 }
5471
5472 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5473 return TRUE;
5474 }
5475
5476 static bool
necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy * policy,struct necp_kernel_socket_policy ** __indexable policy_array,int valid_indices)5477 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5478 {
5479 bool can_skip = FALSE;
5480 u_int32_t highest_skip_session_order = 0;
5481 u_int32_t highest_skip_order = 0;
5482 int i;
5483 for (i = 0; i < valid_indices; i++) {
5484 struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5485
5486 // For policies in a skip window, we can't mark conflicting policies as unnecessary
5487 if (can_skip) {
5488 if (highest_skip_session_order != compared_policy->session_order ||
5489 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5490 // If we've moved on to the next session, or passed the skip window
5491 highest_skip_session_order = 0;
5492 highest_skip_order = 0;
5493 can_skip = FALSE;
5494 } else {
5495 // If this policy is also a skip, in can increase the skip window
5496 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5497 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5498 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5499 }
5500 }
5501 continue;
5502 }
5503 }
5504
5505 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5506 // This policy is a skip. Set the skip window accordingly
5507 can_skip = TRUE;
5508 highest_skip_session_order = compared_policy->session_order;
5509 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5510 }
5511
5512 // The result of the compared policy must be able to block out this policy result
5513 if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5514 continue;
5515 }
5516
5517 // If new policy matches All Interfaces, compared policy must also
5518 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5519 continue;
5520 }
5521
5522 // If new policy matches Local Networks, compared policy must also
5523 if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5524 policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5525 continue;
5526 }
5527
5528 // Default makes lower policies unecessary always
5529 if (compared_policy->condition_mask == 0) {
5530 return TRUE;
5531 }
5532
5533 // Compared must be more general than policy, and include only conditions within policy
5534 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5535 continue;
5536 }
5537
5538 // Negative conditions must match for the overlapping conditions
5539 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5540 continue;
5541 }
5542
5543 if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5544 compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5545 strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5546 continue;
5547 }
5548
5549 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5550 compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5551 continue;
5552 }
5553
5554 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5555 strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5556 continue;
5557 }
5558
5559 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5560 strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5561 continue;
5562 }
5563
5564 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5565 compared_policy->cond_account_id != policy->cond_account_id) {
5566 continue;
5567 }
5568
5569 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5570 compared_policy->cond_policy_id != policy->cond_policy_id) {
5571 continue;
5572 }
5573
5574 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5575 compared_policy->cond_app_id != policy->cond_app_id) {
5576 continue;
5577 }
5578
5579 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5580 compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5581 continue;
5582 }
5583
5584 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5585 (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5586 continue;
5587 }
5588
5589 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5590 compared_policy->cond_uid != policy->cond_uid) {
5591 continue;
5592 }
5593
5594 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5595 compared_policy->cond_real_uid != policy->cond_real_uid) {
5596 continue;
5597 }
5598
5599 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5600 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5601 continue;
5602 }
5603
5604 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5605 compared_policy->cond_protocol != policy->cond_protocol) {
5606 continue;
5607 }
5608
5609 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5610 compared_policy->cond_client_flags != policy->cond_client_flags) {
5611 continue;
5612 }
5613
5614 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5615 !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5616 compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5617 continue;
5618 }
5619
5620 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5621 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5622 if (!necp_is_range_in_range(SA(&policy->cond_local_start), SA(&policy->cond_local_end), SA(&compared_policy->cond_local_start), SA(&compared_policy->cond_local_end))) {
5623 continue;
5624 }
5625 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5626 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5627 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5628 continue;
5629 }
5630 }
5631 }
5632
5633 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5634 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5635 if (!necp_is_range_in_range(SA(&policy->cond_remote_start), SA(&policy->cond_remote_end), SA(&compared_policy->cond_remote_start), SA(&compared_policy->cond_remote_end))) {
5636 continue;
5637 }
5638 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5639 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5640 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5641 continue;
5642 }
5643 }
5644 }
5645
5646 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5647 memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5648 continue;
5649 }
5650
5651 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5652 memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5653 continue;
5654 }
5655
5656 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5657 memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5658 continue;
5659 }
5660
5661 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5662 memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5663 continue;
5664 }
5665
5666 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5667 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5668 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5669 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5670 continue;
5671 }
5672
5673 return TRUE;
5674 }
5675
5676 return FALSE;
5677 }
5678
5679 static bool
necp_kernel_socket_policies_reprocess(void)5680 necp_kernel_socket_policies_reprocess(void)
5681 {
5682 int app_i;
5683 int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5684 int app_layer_current_free_index = 0;
5685 struct necp_kernel_socket_policy *kernel_policy = NULL;
5686
5687 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5688
5689 // Reset mask to 0
5690 necp_kernel_application_policies_condition_mask = 0;
5691 necp_kernel_socket_policies_condition_mask = 0;
5692 necp_kernel_application_policies_count = 0;
5693 necp_kernel_socket_policies_count = 0;
5694 necp_kernel_socket_policies_non_app_count = 0;
5695
5696 // Reset all maps to NULL
5697 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5698 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5699 kfree_type(struct necp_kernel_socket_policy *,
5700 necp_kernel_socket_policies_map_counts[app_i] + 1,
5701 necp_kernel_socket_policies_map[app_i]);
5702 necp_kernel_socket_policies_map[app_i] = NULL;
5703 }
5704
5705 // Init counts
5706 necp_kernel_socket_policies_map_counts[app_i] = 0;
5707 }
5708 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5709 kfree_type(struct necp_kernel_socket_policy *,
5710 necp_kernel_socket_policies_app_layer_map_count + 1,
5711 necp_kernel_socket_policies_app_layer_map);
5712 }
5713 necp_kernel_socket_policies_app_layer_map = NULL;
5714 necp_kernel_socket_policies_app_layer_map_count = 0;
5715
5716 // Create masks and counts
5717 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5718 // App layer mask/count
5719 necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5720 necp_kernel_application_policies_count++;
5721 necp_kernel_socket_policies_app_layer_map_count++;
5722
5723 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5724 // Agent type conditions only apply to app layer
5725 continue;
5726 }
5727
5728 // Update socket layer bucket mask/counts
5729 necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5730 necp_kernel_socket_policies_count++;
5731
5732 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5733 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5734 necp_kernel_socket_policies_non_app_count++;
5735 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5736 necp_kernel_socket_policies_map_counts[app_i]++;
5737 }
5738 } else {
5739 necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5740 }
5741 }
5742
5743 // Allocate maps
5744 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5745 if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5746 // Allocate a NULL-terminated array of policy pointers for each bucket
5747 necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5748 necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5749 if (necp_kernel_socket_policies_map[app_i] == NULL) {
5750 goto fail;
5751 }
5752 }
5753 bucket_current_free_index[app_i] = 0;
5754 }
5755 necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5756 necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5757 if (necp_kernel_socket_policies_app_layer_map == NULL) {
5758 goto fail;
5759 }
5760
5761 // Fill out maps
5762 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5763 // Add app layer policies
5764 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5765 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5766 app_layer_current_free_index++;
5767 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5768 }
5769
5770 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5771 // Agent type conditions only apply to app layer
5772 continue;
5773 }
5774
5775 // Add socket policies
5776 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5777 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5778 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5779 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_map[app_i], bucket_current_free_index[app_i])) {
5780 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5781 bucket_current_free_index[app_i]++;
5782 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5783 }
5784 }
5785 } else {
5786 app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5787 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_map[app_i], bucket_current_free_index[app_i])) {
5788 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5789 bucket_current_free_index[app_i]++;
5790 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5791 }
5792 }
5793 }
5794 necp_kernel_socket_policies_dump_all();
5795 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5796 return TRUE;
5797
5798 fail:
5799 // Free memory, reset masks to 0
5800 necp_kernel_application_policies_condition_mask = 0;
5801 necp_kernel_socket_policies_condition_mask = 0;
5802 necp_kernel_application_policies_count = 0;
5803 necp_kernel_socket_policies_count = 0;
5804 necp_kernel_socket_policies_non_app_count = 0;
5805 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5806 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5807 kfree_type(struct necp_kernel_socket_policy *,
5808 necp_kernel_socket_policies_map_counts[app_i] + 1,
5809 necp_kernel_socket_policies_map[app_i]);
5810 necp_kernel_socket_policies_map[app_i] = NULL;
5811 }
5812 necp_kernel_socket_policies_map_counts[app_i] = 0;
5813 }
5814 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5815 kfree_type(struct necp_kernel_socket_policy *,
5816 necp_kernel_socket_policies_app_layer_map_count + 1,
5817 necp_kernel_socket_policies_app_layer_map);
5818 necp_kernel_socket_policies_app_layer_map = NULL;
5819 }
5820 necp_kernel_socket_policies_app_layer_map_count = 0;
5821 return FALSE;
5822 }
5823
5824 static u_int32_t
necp_get_new_string_id(void)5825 necp_get_new_string_id(void)
5826 {
5827 static u_int32_t necp_last_string_id = 0;
5828
5829 u_int32_t newid = 0;
5830
5831 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5832
5833 bool wrapped = FALSE;
5834 do {
5835 necp_last_string_id++;
5836 if (necp_last_string_id < 1) {
5837 if (wrapped) {
5838 // Already wrapped, give up
5839 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5840 return 0;
5841 }
5842 necp_last_string_id = 1;
5843 wrapped = TRUE;
5844 }
5845 newid = necp_last_string_id;
5846 } while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5847
5848 if (newid == 0) {
5849 NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5850 return 0;
5851 }
5852
5853 return newid;
5854 }
5855
5856 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5857 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5858 {
5859 struct necp_string_id_mapping *searchentry = NULL;
5860 struct necp_string_id_mapping *foundentry = NULL;
5861
5862 LIST_FOREACH(searchentry, list, chain) {
5863 if (strcmp(searchentry->string, string) == 0) {
5864 foundentry = searchentry;
5865 break;
5866 }
5867 }
5868
5869 return foundentry;
5870 }
5871
5872 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5873 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5874 {
5875 struct necp_string_id_mapping *searchentry = NULL;
5876 struct necp_string_id_mapping *foundentry = NULL;
5877
5878 LIST_FOREACH(searchentry, list, chain) {
5879 if (searchentry->id == local_id) {
5880 foundentry = searchentry;
5881 break;
5882 }
5883 }
5884
5885 return foundentry;
5886 }
5887
5888 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5889 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5890 {
5891 u_int32_t string_id = 0;
5892 struct necp_string_id_mapping *existing_mapping = NULL;
5893
5894 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5895
5896 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5897 if (existing_mapping != NULL) {
5898 string_id = existing_mapping->id;
5899 os_ref_retain_locked(&existing_mapping->refcount);
5900 } else {
5901 struct necp_string_id_mapping * __single new_mapping = NULL;
5902 new_mapping = kalloc_type(struct necp_string_id_mapping,
5903 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5904
5905 size_t length = strlen(string) + 1;
5906 char *buffer = kalloc_data(length, Z_WAITOK);
5907 if (buffer != NULL) {
5908 strlcpy(buffer, string, length);
5909 new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5910 new_mapping->id = necp_get_new_string_id();
5911 os_ref_init(&new_mapping->refcount, &necp_refgrp);
5912 LIST_INSERT_HEAD(list, new_mapping, chain);
5913 string_id = new_mapping->id;
5914 } else {
5915 kfree_type(struct necp_string_id_mapping, new_mapping);
5916 new_mapping = NULL;
5917 }
5918 }
5919 return string_id;
5920 }
5921
5922 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5923 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5924 {
5925 struct necp_string_id_mapping * __single existing_mapping = NULL;
5926 char * __indexable buffer = NULL;
5927
5928 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5929
5930 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5931 if (existing_mapping != NULL) {
5932 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5933 LIST_REMOVE(existing_mapping, chain);
5934 buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5935 kfree_data_addr(buffer);
5936 kfree_type(struct necp_string_id_mapping, existing_mapping);
5937 }
5938 return TRUE;
5939 }
5940
5941 return FALSE;
5942 }
5943
5944 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5945 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5946 {
5947 struct necp_domain_filter *searchfilter = NULL;
5948 struct necp_domain_filter *foundfilter = NULL;
5949
5950 LIST_FOREACH(searchfilter, list, chain) {
5951 if (searchfilter->id == filter_id) {
5952 foundfilter = searchfilter;
5953 break;
5954 }
5955 }
5956
5957 return foundfilter;
5958 }
5959
5960 static u_int32_t
necp_get_new_domain_filter_id(void)5961 necp_get_new_domain_filter_id(void)
5962 {
5963 static u_int32_t necp_last_filter_id = 0;
5964
5965 u_int32_t newid = 0;
5966
5967 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5968
5969 bool wrapped = FALSE;
5970 do {
5971 // Scope id within its space
5972 if (++necp_last_filter_id > NECP_DOMAIN_FILTER_ID_MAX) {
5973 necp_last_filter_id = 0;
5974 }
5975 if (necp_last_filter_id < 1) {
5976 if (wrapped) {
5977 // Already wrapped, give up
5978 NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5979 return 0;
5980 }
5981 necp_last_filter_id = 1;
5982 wrapped = TRUE;
5983 }
5984 newid = necp_last_filter_id;
5985 } while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5986
5987 if (newid == 0) {
5988 NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5989 return 0;
5990 }
5991
5992 return newid;
5993 }
5994
5995 static u_int32_t
necp_create_domain_filter(struct necp_domain_filter_list * list,struct necp_domain_filter_list * owner_list,struct net_bloom_filter * filter)5996 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5997 {
5998 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5999
6000 struct necp_domain_filter *new_filter = NULL;
6001 new_filter = kalloc_type(struct necp_domain_filter,
6002 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6003
6004 new_filter->filter = filter;
6005 new_filter->id = necp_get_new_domain_filter_id();
6006 LIST_INSERT_HEAD(list, new_filter, chain);
6007 LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
6008 os_ref_init(&new_filter->refcount, &necp_refgrp);
6009
6010 return new_filter->id;
6011 }
6012
6013 static bool
necp_remove_domain_filter(struct necp_domain_filter_list * list,__unused struct necp_domain_filter_list * owner_list,u_int32_t filter_id)6014 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
6015 {
6016 struct necp_domain_filter * __single existing_filter = NULL;
6017
6018 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6019
6020 existing_filter = necp_lookup_domain_filter(list, filter_id);
6021 if (existing_filter != NULL) {
6022 if (os_ref_release_locked(&existing_filter->refcount) == 0) {
6023 LIST_REMOVE(existing_filter, chain);
6024 LIST_REMOVE(existing_filter, owner_chain);
6025 net_bloom_filter_destroy(existing_filter->filter);
6026 kfree_type(struct necp_domain_filter, existing_filter);
6027 }
6028 return true;
6029 }
6030
6031 return false;
6032 }
6033
6034 static struct necp_domain_trie *
necp_lookup_domain_trie(struct necp_domain_trie_list * list,u_int32_t id)6035 necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id)
6036 {
6037 struct necp_domain_trie *searchTrie = NULL;
6038 struct necp_domain_trie *foundTrie = NULL;
6039
6040 LIST_FOREACH(searchTrie, list, chain) {
6041 if (searchTrie->id == id) {
6042 foundTrie = searchTrie;
6043 break;
6044 }
6045 }
6046
6047 return foundTrie;
6048 }
6049
6050 static u_int32_t
necp_get_new_domain_trie_id(void)6051 necp_get_new_domain_trie_id(void)
6052 {
6053 static u_int32_t necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START;
6054 u_int32_t newid = necp_last_trie_id;
6055
6056 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6057
6058 bool wrapped = FALSE;
6059 do {
6060 if (++necp_last_trie_id < NECP_DOMAIN_TRIE_ID_START + 1) {
6061 if (wrapped) {
6062 // Already wrapped, give up
6063 NECPLOG0(LOG_ERR, "Failed to find a free trie ID.\n");
6064 return 0;
6065 }
6066 necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START + 1;
6067 wrapped = TRUE;
6068 }
6069 newid = necp_last_trie_id;
6070 } while (necp_lookup_domain_trie(&necp_global_domain_trie_list, newid) != NULL); // If already used, keep trying
6071
6072 if (newid == NECP_DOMAIN_TRIE_ID_START) {
6073 NECPLOG0(LOG_ERR, "Allocate trie id failed.\n");
6074 return 0;
6075 }
6076
6077 return newid;
6078 }
6079
6080 static u_int32_t
necp_create_domain_trie(struct necp_domain_trie_list * list,struct necp_domain_trie_list * owner_list,struct necp_domain_trie_request * trie_request,size_t trie_request_size)6081 necp_create_domain_trie(struct necp_domain_trie_list *list,
6082 struct necp_domain_trie_list *owner_list,
6083 struct necp_domain_trie_request *trie_request, size_t trie_request_size)
6084 {
6085 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6086
6087 struct necp_domain_trie *new_trie = NULL;
6088 new_trie = kalloc_type(struct necp_domain_trie, Z_WAITOK | Z_ZERO | Z_NOFAIL);
6089 if (new_trie == NULL) {
6090 NECPLOG0(LOG_ERR, "Failed to allow domain trie\n");
6091 return 0;
6092 }
6093
6094 if (net_trie_init_with_mem(&new_trie->trie, trie_request->data, trie_request->total_mem_size,
6095 trie_request->nodes_mem_size, trie_request->maps_mem_size, trie_request->bytes_mem_size,
6096 trie_request->nodes_count, trie_request->maps_count, trie_request->bytes_count) == false) {
6097 NECPLOG0(LOG_ERR, "Failed to initialize domain trie\n");
6098 kfree_type(struct necp_domain_trie, new_trie);
6099 return 0;
6100 }
6101 new_trie->trie_request = trie_request;
6102 new_trie->trie_request_size = trie_request_size;
6103 new_trie->id = necp_get_new_domain_trie_id();
6104 new_trie->trie_request->id = new_trie->id;
6105 LIST_INSERT_HEAD(list, new_trie, chain);
6106 LIST_INSERT_HEAD(owner_list, new_trie, owner_chain);
6107
6108 os_ref_init(&new_trie->refcount, &necp_refgrp);
6109 necp_trie_count++;
6110 return new_trie->id;
6111 }
6112
6113 static void
necp_free_domain_trie(struct necp_domain_trie * existing_trie)6114 necp_free_domain_trie(struct necp_domain_trie *existing_trie)
6115 {
6116 if (existing_trie != NULL) {
6117 uint8_t *necp_trie_request_buffer = (uint8_t *)existing_trie->trie_request;
6118 kfree_data(necp_trie_request_buffer, existing_trie->trie_request_size);
6119 kfree_type(struct necp_domain_trie, existing_trie);
6120 }
6121 }
6122
6123 static bool
necp_remove_domain_trie(struct necp_domain_trie_list * list,__unused struct necp_domain_trie_list * owner_list,u_int32_t id)6124 necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id)
6125 {
6126 struct necp_domain_trie * __single existing_trie = NULL;
6127
6128 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6129
6130 existing_trie = necp_lookup_domain_trie(list, id);
6131 if (existing_trie != NULL) {
6132 if (os_ref_release_locked(&existing_trie->refcount) == 0) {
6133 LIST_REMOVE(existing_trie, chain);
6134 LIST_REMOVE(existing_trie, owner_chain);
6135 necp_free_domain_trie(existing_trie);
6136 necp_trie_count--;
6137 }
6138 return true;
6139 }
6140
6141 return false;
6142 }
6143
6144 static Boolean
necp_match_domain_with_trie(struct necp_domain_trie_list * list,u_int32_t id,char * __sized_by (length)domain,size_t length)6145 necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length)
6146 {
6147 size_t metadata_length = 0;
6148 const uint8_t * __sized_by(metadata_length) metadata = NULL;
6149
6150 struct necp_domain_trie *necp_trie = necp_lookup_domain_trie(list, id);
6151 if (necp_trie == NULL || necp_trie->trie_request == NULL) {
6152 return false;
6153 }
6154 Boolean reverse = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_REVERSE_SEARCH);
6155 Boolean allow_partial_match = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_ALLOW_PARTIAL_MATCH);
6156 return net_trie_search(&necp_trie->trie, (const uint8_t *)domain, length,
6157 &metadata, &metadata_length, reverse, allow_partial_match, necp_trie->trie_request->partial_match_terminator, NULL, NULL) != NULL_TRIE_IDX;
6158 }
6159
6160 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
6161 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
6162 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)6163 necp_get_new_route_rule_id(bool aggregate)
6164 {
6165 static u_int32_t necp_last_route_rule_id = 0;
6166 static u_int32_t necp_last_aggregate_route_rule_id = 0;
6167
6168 u_int32_t newid = 0;
6169
6170 if (!aggregate) {
6171 // Main necp_kernel_policy_lock protects non-aggregate rule IDs
6172 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6173
6174 bool wrapped = FALSE;
6175 do {
6176 necp_last_route_rule_id++;
6177 if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
6178 necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6179 if (wrapped) {
6180 // Already wrapped, give up
6181 NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
6182 return 0;
6183 }
6184 necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
6185 wrapped = TRUE;
6186 }
6187 newid = necp_last_route_rule_id;
6188 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6189 } else {
6190 // necp_route_rule_lock protects aggregate rule IDs
6191 LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
6192
6193 bool wrapped = FALSE;
6194 do {
6195 necp_last_aggregate_route_rule_id++;
6196 if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6197 if (wrapped) {
6198 // Already wrapped, give up
6199 NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
6200 return 0;
6201 }
6202 necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
6203 wrapped = TRUE;
6204 }
6205 newid = necp_last_aggregate_route_rule_id;
6206 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6207 }
6208
6209 if (newid == 0) {
6210 NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
6211 return 0;
6212 }
6213
6214 return newid;
6215 }
6216
6217 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)6218 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6219 {
6220 struct necp_route_rule *searchentry = NULL;
6221 struct necp_route_rule *foundentry = NULL;
6222
6223 LIST_FOREACH(searchentry, list, chain) {
6224 if (searchentry->id == route_rule_id) {
6225 foundentry = searchentry;
6226 break;
6227 }
6228 }
6229
6230 return foundentry;
6231 }
6232
6233 static struct necp_route_rule *
necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list * list,u_int8_t default_action,u_int8_t cellular_action,u_int8_t wifi_action,u_int8_t wired_action,u_int8_t expensive_action,u_int8_t constrained_action,u_int8_t companion_action,u_int8_t vpn_action,u_int32_t * __indexable if_indices,u_int8_t * __indexable if_actions,uuid_t netagent_uuid,uuid_t match_netagent_uuid,u_int32_t control_unit,u_int32_t effective_type)6234 necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list *list, u_int8_t default_action, u_int8_t cellular_action, u_int8_t wifi_action, u_int8_t wired_action, u_int8_t expensive_action, u_int8_t constrained_action, u_int8_t companion_action, u_int8_t vpn_action, u_int32_t * __indexable if_indices, u_int8_t * __indexable if_actions, uuid_t netagent_uuid, uuid_t match_netagent_uuid, u_int32_t control_unit, u_int32_t effective_type)
6235 {
6236 struct necp_route_rule *searchentry = NULL;
6237 struct necp_route_rule *foundentry = NULL;
6238
6239 LIST_FOREACH(searchentry, list, chain) {
6240 if (searchentry->default_action == default_action &&
6241 searchentry->cellular_action == cellular_action &&
6242 searchentry->wifi_action == wifi_action &&
6243 searchentry->wired_action == wired_action &&
6244 searchentry->expensive_action == expensive_action &&
6245 searchentry->constrained_action == constrained_action &&
6246 searchentry->companion_action == companion_action &&
6247 searchentry->vpn_action == vpn_action &&
6248 searchentry->control_unit == control_unit &&
6249 searchentry->effective_type == effective_type) {
6250 bool match_failed = FALSE;
6251 size_t index_a = 0;
6252 size_t index_b = 0;
6253 size_t count_a = 0;
6254 size_t count_b = 0;
6255 for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
6256 bool found_index = FALSE;
6257 if (searchentry->exception_if_indices[index_a] == 0) {
6258 break;
6259 }
6260 count_a++;
6261 for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
6262 if (if_indices[index_b] == 0) {
6263 break;
6264 }
6265 if (index_b >= count_b) {
6266 count_b = index_b + 1;
6267 }
6268 if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
6269 searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
6270 found_index = TRUE;
6271 break;
6272 }
6273 }
6274 if (!found_index) {
6275 match_failed = TRUE;
6276 break;
6277 }
6278 }
6279
6280 if (match_failed || count_a != count_b) {
6281 continue;
6282 }
6283
6284 bool has_agent_a = !uuid_is_null(netagent_uuid);
6285 bool has_agent_b = (searchentry->netagent_id != 0);
6286 if (has_agent_a != has_agent_b) {
6287 continue;
6288 }
6289
6290 if (has_agent_a) {
6291 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
6292 if (mapping == NULL) {
6293 // Bad mapping, doesn't match
6294 continue;
6295 }
6296 if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
6297 // UUIDs don't match
6298 continue;
6299 }
6300 }
6301
6302 bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
6303 bool has_match_agent_b = (searchentry->match_netagent_id != 0);
6304 if (has_match_agent_a != has_match_agent_b) {
6305 continue;
6306 }
6307
6308 if (has_match_agent_a) {
6309 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->match_netagent_id);
6310 if (mapping == NULL) {
6311 // Bad mapping, doesn't match
6312 continue;
6313 }
6314 if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
6315 // UUIDs don't match
6316 continue;
6317 }
6318 }
6319
6320 // Rules match!
6321 foundentry = searchentry;
6322 break;
6323 }
6324 }
6325
6326 return foundentry;
6327 }
6328
6329 static u_int32_t
necp_create_route_rule(struct necp_route_rule_list * list,u_int8_t * __sized_by (route_rules_array_size)route_rules_array,u_int32_t route_rules_array_size,bool * has_socket_only_actions)6330 necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size,
6331 bool *has_socket_only_actions)
6332 {
6333 size_t offset = 0;
6334 u_int32_t route_rule_id = 0;
6335 struct necp_route_rule *existing_rule = NULL;
6336 u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
6337 u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
6338 u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
6339 u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
6340 u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
6341 u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
6342 u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
6343 u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
6344 u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
6345 size_t num_valid_indices = 0;
6346 memset(&if_indices, 0, sizeof(if_indices));
6347 u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
6348 memset(&if_actions, 0, sizeof(if_actions));
6349
6350 uuid_t netagent_uuid = {};
6351
6352 uuid_t match_netagent_uuid = {};
6353 uint32_t control_unit = 0;
6354 uint32_t effective_type = 0;
6355
6356 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6357
6358 if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6359 return 0;
6360 }
6361
6362 // Process rules
6363 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6364 ifnet_t __single rule_interface = NULL;
6365 char interface_name[IFXNAMSIZ];
6366 u_int32_t length = 0;
6367 u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6368
6369 if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6370 // Invalid TLV goes beyond end of the rules array
6371 break;
6372 }
6373
6374 // Increment offset for the next time through the loop
6375 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6376
6377 u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6378 u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6379 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6380 u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6381
6382 if (rule_action == NECP_ROUTE_RULE_NONE) {
6383 // Don't allow an explicit rule to be None action
6384 continue;
6385 }
6386
6387 if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6388 rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6389 if (rule_length < sizeof(uuid_t)) {
6390 // Too short, skip
6391 continue;
6392 }
6393
6394 if (!uuid_is_null(netagent_uuid)) {
6395 if (uuid_compare(netagent_uuid, rule_value) != 0) {
6396 // UUIDs don't match, skip
6397 continue;
6398 }
6399 } else {
6400 // Copy out agent UUID
6401 memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6402 }
6403
6404 // Adjust remaining length
6405 rule_value += sizeof(netagent_uuid);
6406 rule_length -= sizeof(netagent_uuid);
6407 *has_socket_only_actions = true;
6408 } else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6409 if (rule_length < sizeof(control_unit)) {
6410 // Too short, skip
6411 continue;
6412 }
6413
6414 memcpy(&control_unit, rule_value, sizeof(control_unit));
6415
6416 // Adjust remaining length
6417 rule_value += sizeof(control_unit);
6418 rule_length -= sizeof(control_unit);
6419 *has_socket_only_actions = true;
6420 } else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6421 if (rule_length < sizeof(effective_type)) {
6422 // Too short, skip
6423 continue;
6424 }
6425
6426 memcpy(&effective_type, rule_value, sizeof(effective_type));
6427
6428 // Adjust remaining length
6429 rule_value += sizeof(effective_type);
6430 rule_length -= sizeof(effective_type);
6431 }
6432
6433 if (rule_length == 0) {
6434 if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6435 cellular_action = rule_action;
6436 }
6437 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6438 wifi_action = rule_action;
6439 }
6440 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6441 wired_action = rule_action;
6442 }
6443 if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6444 expensive_action = rule_action;
6445 }
6446 if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6447 constrained_action = rule_action;
6448 }
6449 if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6450 companion_action = rule_action;
6451 }
6452 if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6453 vpn_action = rule_action;
6454 }
6455 if (rule_flags == 0) {
6456 default_action = rule_action;
6457 }
6458 continue;
6459 } else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6460 if (rule_length < sizeof(uuid_t)) {
6461 // Too short, skip
6462 continue;
6463 }
6464
6465 // Store the netagent UUID to match
6466 memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6467 // If the data is exactly a UUID, this is the default action
6468 if (rule_length == sizeof(uuid_t)) {
6469 default_action = rule_action;
6470 continue;
6471 }
6472
6473 // If the data is longer than a UUID, this also includes an interface name
6474 // Adjust remaining length to make sure the interface name is picked up below
6475 rule_value += sizeof(uuid_t);
6476 rule_length -= sizeof(uuid_t);
6477 }
6478
6479 if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6480 continue;
6481 }
6482
6483 if (rule_length <= IFXNAMSIZ) {
6484 memcpy(interface_name, rule_value, rule_length);
6485 interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6486 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6487 if_actions[num_valid_indices] = rule_action;
6488 if_indices[num_valid_indices++] = rule_interface->if_index;
6489 ifnet_release(rule_interface);
6490 }
6491 }
6492 }
6493
6494 existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, companion_action, vpn_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit, effective_type);
6495 if (existing_rule != NULL) {
6496 route_rule_id = existing_rule->id;
6497 os_ref_retain_locked(&existing_rule->refcount);
6498 } else {
6499 struct necp_route_rule *new_rule = NULL;
6500 new_rule = kalloc_type(struct necp_route_rule,
6501 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6502 route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6503 if (!uuid_is_null(netagent_uuid)) {
6504 new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
6505 }
6506 if (!uuid_is_null(match_netagent_uuid)) {
6507 new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(match_netagent_uuid);
6508 }
6509 new_rule->effective_type = effective_type;
6510 new_rule->control_unit = control_unit;
6511 new_rule->default_action = default_action;
6512 new_rule->cellular_action = cellular_action;
6513 new_rule->wifi_action = wifi_action;
6514 new_rule->wired_action = wired_action;
6515 new_rule->expensive_action = expensive_action;
6516 new_rule->constrained_action = constrained_action;
6517 new_rule->companion_action = companion_action;
6518 new_rule->vpn_action = vpn_action;
6519 memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6520 memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6521 os_ref_init(&new_rule->refcount, &necp_refgrp);
6522 LIST_INSERT_HEAD(list, new_rule, chain);
6523 }
6524 return route_rule_id;
6525 }
6526
6527 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6528 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6529 {
6530 if (rule_id) {
6531 lck_rw_lock_exclusive(&necp_route_rule_lock);
6532
6533 struct necp_aggregate_route_rule * __single existing_rule = NULL;
6534 struct necp_aggregate_route_rule *tmp_rule = NULL;
6535
6536 LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6537 int index = 0;
6538 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6539 u_int32_t route_rule_id = existing_rule->rule_ids[index];
6540 if (route_rule_id == rule_id) {
6541 LIST_REMOVE(existing_rule, chain);
6542 kfree_type(struct necp_aggregate_route_rule, existing_rule);
6543 break;
6544 }
6545 }
6546 }
6547
6548 lck_rw_done(&necp_route_rule_lock);
6549 }
6550 }
6551
6552 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6553 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6554 {
6555 struct necp_route_rule * __single existing_rule = NULL;
6556
6557 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6558
6559 existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6560 if (existing_rule != NULL) {
6561 if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6562 necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6563 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
6564 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->match_netagent_id);
6565 LIST_REMOVE(existing_rule, chain);
6566 kfree_type(struct necp_route_rule, existing_rule);
6567 }
6568 return TRUE;
6569 }
6570
6571 return FALSE;
6572 }
6573
6574 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6575 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6576 {
6577 struct necp_aggregate_route_rule *searchentry = NULL;
6578 struct necp_aggregate_route_rule *foundentry = NULL;
6579
6580 lck_rw_lock_shared(&necp_route_rule_lock);
6581
6582 LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6583 if (searchentry->id == route_rule_id) {
6584 foundentry = searchentry;
6585 break;
6586 }
6587 }
6588
6589 lck_rw_done(&necp_route_rule_lock);
6590
6591 return foundentry;
6592 }
6593
6594 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6595 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6596 {
6597 u_int32_t aggregate_route_rule_id = 0;
6598 struct necp_aggregate_route_rule *new_rule = NULL;
6599 struct necp_aggregate_route_rule *existing_rule = NULL;
6600
6601 lck_rw_lock_exclusive(&necp_route_rule_lock);
6602
6603 // Check if the rule already exists
6604 LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6605 if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6606 lck_rw_done(&necp_route_rule_lock);
6607 return existing_rule->id;
6608 }
6609 }
6610
6611 new_rule = kalloc_type(struct necp_aggregate_route_rule,
6612 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6613 aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6614 new_rule->id = aggregate_route_rule_id;
6615 memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6616 LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6617 lck_rw_done(&necp_route_rule_lock);
6618
6619 return aggregate_route_rule_id;
6620 }
6621
6622 #define NECP_NULL_SERVICE_ID 1
6623 #define NECP_FIRST_VALID_SERVICE_ID 2
6624 #define NECP_FIRST_VALID_APP_ID UINT16_MAX
6625 static u_int32_t
necp_get_new_uuid_id(bool service)6626 necp_get_new_uuid_id(bool service)
6627 {
6628 static u_int32_t necp_last_service_uuid_id = 0;
6629 static u_int32_t necp_last_app_uuid_id = 0;
6630
6631 u_int32_t newid = 0;
6632
6633 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6634
6635 if (service) {
6636 bool wrapped = FALSE;
6637 do {
6638 necp_last_service_uuid_id++;
6639 if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
6640 necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
6641 if (wrapped) {
6642 // Already wrapped, give up
6643 NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
6644 return NECP_NULL_SERVICE_ID;
6645 }
6646 necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
6647 wrapped = TRUE;
6648 }
6649 newid = necp_last_service_uuid_id;
6650 } while (necp_uuid_lookup_uuid_with_service_id_locked(newid) != NULL); // If already used, keep trying
6651 } else {
6652 bool wrapped = FALSE;
6653 do {
6654 necp_last_app_uuid_id++;
6655 if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
6656 if (wrapped) {
6657 // Already wrapped, give up
6658 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
6659 return NECP_NULL_SERVICE_ID;
6660 }
6661 necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
6662 wrapped = TRUE;
6663 }
6664 newid = necp_last_app_uuid_id;
6665 } while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6666 }
6667
6668 if (newid == NECP_NULL_SERVICE_ID) {
6669 NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
6670 return NECP_NULL_SERVICE_ID;
6671 }
6672
6673 return newid;
6674 }
6675
6676 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6677 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6678 {
6679 struct necp_uuid_id_mapping *searchentry = NULL;
6680 struct necp_uuid_id_mapping *foundentry = NULL;
6681
6682 LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6683 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6684 foundentry = searchentry;
6685 break;
6686 }
6687 }
6688
6689 return foundentry;
6690 }
6691
6692 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6693 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6694 {
6695 struct necp_uuid_id_mapping *searchentry = NULL;
6696 struct necp_uuid_id_mapping *foundentry = NULL;
6697
6698 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6699 for (uuid_list_head = &necp_uuid_app_id_hashtbl[necp_uuid_app_id_hash_num_buckets - 1]; uuid_list_head >= necp_uuid_app_id_hashtbl; uuid_list_head--) {
6700 LIST_FOREACH(searchentry, uuid_list_head, chain) {
6701 if (searchentry->id == local_id) {
6702 foundentry = searchentry;
6703 break;
6704 }
6705 }
6706 }
6707
6708 return foundentry;
6709 }
6710
6711 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6712 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6713 {
6714 u_int32_t local_id = 0;
6715 struct necp_uuid_id_mapping *existing_mapping = NULL;
6716
6717 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6718
6719 if (allocated_mapping) {
6720 *allocated_mapping = FALSE;
6721 }
6722
6723 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6724 if (existing_mapping != NULL) {
6725 local_id = existing_mapping->id;
6726 os_ref_retain_locked(&existing_mapping->refcount);
6727 if (uuid_policy_table) {
6728 existing_mapping->table_usecount++;
6729 }
6730 } else {
6731 struct necp_uuid_id_mapping *new_mapping = NULL;
6732 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6733 Z_WAITOK | Z_NOFAIL);
6734 uuid_copy(new_mapping->uuid, uuid);
6735 new_mapping->id = necp_get_new_uuid_id(false);
6736 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6737 if (uuid_policy_table) {
6738 new_mapping->table_usecount = 1;
6739 } else {
6740 new_mapping->table_usecount = 0;
6741 }
6742
6743 LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6744
6745 if (allocated_mapping) {
6746 *allocated_mapping = TRUE;
6747 }
6748
6749 local_id = new_mapping->id;
6750 }
6751
6752 return local_id;
6753 }
6754
6755 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6756 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6757 {
6758 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6759
6760 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6761
6762 if (removed_mapping) {
6763 *removed_mapping = FALSE;
6764 }
6765
6766 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6767 if (existing_mapping != NULL) {
6768 if (uuid_policy_table) {
6769 existing_mapping->table_usecount--;
6770 }
6771 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6772 LIST_REMOVE(existing_mapping, chain);
6773 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6774 if (removed_mapping) {
6775 *removed_mapping = TRUE;
6776 }
6777 }
6778 return TRUE;
6779 }
6780
6781 return FALSE;
6782 }
6783
6784 static struct necp_uuid_id_mapping *
necp_uuid_get_null_service_id_mapping(void)6785 necp_uuid_get_null_service_id_mapping(void)
6786 {
6787 static struct necp_uuid_id_mapping null_mapping;
6788 uuid_clear(null_mapping.uuid);
6789 null_mapping.id = NECP_NULL_SERVICE_ID;
6790
6791 return &null_mapping;
6792 }
6793
6794 static struct necp_uuid_id_mapping *
necp_uuid_lookup_service_id_locked(uuid_t uuid)6795 necp_uuid_lookup_service_id_locked(uuid_t uuid)
6796 {
6797 struct necp_uuid_id_mapping *searchentry = NULL;
6798 struct necp_uuid_id_mapping *foundentry = NULL;
6799
6800 if (uuid_is_null(uuid)) {
6801 return necp_uuid_get_null_service_id_mapping();
6802 }
6803
6804 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6805 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6806 foundentry = searchentry;
6807 break;
6808 }
6809 }
6810
6811 return foundentry;
6812 }
6813
6814 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)6815 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
6816 {
6817 struct necp_uuid_id_mapping *searchentry = NULL;
6818 struct necp_uuid_id_mapping *foundentry = NULL;
6819
6820 if (local_id == NECP_NULL_SERVICE_ID) {
6821 return necp_uuid_get_null_service_id_mapping();
6822 }
6823
6824 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6825 if (searchentry->id == local_id) {
6826 foundentry = searchentry;
6827 break;
6828 }
6829 }
6830
6831 return foundentry;
6832 }
6833
6834 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid)6835 necp_create_uuid_service_id_mapping(uuid_t uuid)
6836 {
6837 u_int32_t local_id = 0;
6838 struct necp_uuid_id_mapping *existing_mapping = NULL;
6839
6840 if (uuid_is_null(uuid)) {
6841 return NECP_NULL_SERVICE_ID;
6842 }
6843
6844 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6845
6846 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6847 if (existing_mapping != NULL) {
6848 local_id = existing_mapping->id;
6849 os_ref_retain_locked(&existing_mapping->refcount);
6850 } else {
6851 struct necp_uuid_id_mapping *new_mapping = NULL;
6852 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6853 Z_WAITOK | Z_NOFAIL);
6854 uuid_copy(new_mapping->uuid, uuid);
6855 new_mapping->id = necp_get_new_uuid_id(true);
6856 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6857
6858 LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
6859
6860 local_id = new_mapping->id;
6861 }
6862
6863 return local_id;
6864 }
6865
6866 static bool
necp_remove_uuid_service_id_mapping(uuid_t uuid)6867 necp_remove_uuid_service_id_mapping(uuid_t uuid)
6868 {
6869 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6870
6871 if (uuid_is_null(uuid)) {
6872 return TRUE;
6873 }
6874
6875 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6876
6877 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6878 if (existing_mapping != NULL) {
6879 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6880 LIST_REMOVE(existing_mapping, chain);
6881 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6882 }
6883 return TRUE;
6884 }
6885
6886 return FALSE;
6887 }
6888
6889 static bool
necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)6890 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
6891 {
6892 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6893
6894 if (service_id == 0) {
6895 return TRUE;
6896 }
6897
6898 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6899
6900 existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
6901 if (existing_mapping != NULL) {
6902 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6903 LIST_REMOVE(existing_mapping, chain);
6904 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6905 }
6906 return TRUE;
6907 }
6908
6909 return FALSE;
6910 }
6911
6912 static bool
necp_kernel_socket_policies_update_uuid_table(void)6913 necp_kernel_socket_policies_update_uuid_table(void)
6914 {
6915 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6916
6917 if (necp_uuid_app_id_mappings_dirty) {
6918 uuid_t dummy_uuid = {};
6919 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6920 NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6921 return FALSE;
6922 }
6923
6924 if (necp_num_uuid_app_id_mappings > 0) {
6925 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6926 for (uuid_list_head = &necp_uuid_app_id_hashtbl[necp_uuid_app_id_hash_num_buckets - 1]; uuid_list_head >= necp_uuid_app_id_hashtbl; uuid_list_head--) {
6927 struct necp_uuid_id_mapping *mapping = NULL;
6928 LIST_FOREACH(mapping, uuid_list_head, chain) {
6929 if (mapping->table_usecount > 0 &&
6930 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6931 NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6932 }
6933 }
6934 }
6935 }
6936
6937 necp_uuid_app_id_mappings_dirty = FALSE;
6938 }
6939
6940 return TRUE;
6941 }
6942
6943 #define NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS (NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS | NECP_KERNEL_CONDITION_SCHEME_PORT | NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)
6944 static necp_kernel_policy_id
necp_kernel_ip_output_policy_add(necp_policy_order order,necp_policy_order suborder,u_int32_t session_order,int session_pid,u_int64_t condition_mask,u_int64_t condition_negated_mask,necp_kernel_policy_id cond_policy_id,ifnet_t cond_bound_interface,u_int32_t cond_last_interface_index,u_int16_t cond_protocol,union necp_sockaddr_union * cond_local_start,union necp_sockaddr_union * cond_local_end,u_int8_t cond_local_prefix,union necp_sockaddr_union * cond_remote_start,union necp_sockaddr_union * cond_remote_end,u_int8_t cond_remote_prefix,u_int16_t cond_packet_filter_tags,u_int16_t cond_scheme_port,u_int32_t cond_bound_interface_flags,u_int32_t cond_bound_interface_eflags,u_int32_t cond_bound_interface_xflags,u_int8_t cond_local_networks_flags,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)6945 necp_kernel_ip_output_policy_add(necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_kernel_policy_id cond_policy_id, ifnet_t cond_bound_interface, u_int32_t cond_last_interface_index, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
6946 {
6947 struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6948 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6949
6950 new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6951 new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6952 new_kernel_policy->suborder = suborder;
6953 new_kernel_policy->order = order;
6954 new_kernel_policy->session_order = session_order;
6955 new_kernel_policy->session_pid = session_pid;
6956
6957 // Sanitize condition mask
6958 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6959 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6960 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6961 }
6962 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
6963 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
6964 }
6965 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6966 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6967 }
6968 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6969 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6970 }
6971 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6972
6973 // Set condition values
6974 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6975 new_kernel_policy->cond_policy_id = cond_policy_id;
6976 }
6977 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6978 if (cond_bound_interface) {
6979 ifnet_reference(cond_bound_interface);
6980 }
6981 new_kernel_policy->cond_bound_interface = cond_bound_interface;
6982 }
6983 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6984 new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6985 }
6986 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6987 new_kernel_policy->cond_protocol = cond_protocol;
6988 }
6989 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6990 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
6991 }
6992 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6993 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
6994 }
6995 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6996 new_kernel_policy->cond_local_prefix = cond_local_prefix;
6997 }
6998 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6999 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
7000 }
7001 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7002 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
7003 }
7004 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7005 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
7006 }
7007 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
7008 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
7009 }
7010 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7011 new_kernel_policy->cond_scheme_port = cond_scheme_port;
7012 }
7013 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
7014 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
7015 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
7016 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
7017 }
7018 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
7019 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
7020 }
7021
7022 new_kernel_policy->result = result;
7023 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
7024
7025 if (necp_debug) {
7026 NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
7027 }
7028 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
7029
7030 return new_kernel_policy ? new_kernel_policy->id : 0;
7031 }
7032
7033 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)7034 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
7035 {
7036 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7037 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7038
7039 if (policy_id == 0) {
7040 return NULL;
7041 }
7042
7043 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
7044 if (kernel_policy->id == policy_id) {
7045 return kernel_policy;
7046 }
7047 }
7048
7049 return NULL;
7050 }
7051
7052 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)7053 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
7054 {
7055 struct necp_kernel_ip_output_policy * __single policy = NULL;
7056
7057 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7058
7059 policy = necp_kernel_ip_output_policy_find(policy_id);
7060 if (policy) {
7061 LIST_REMOVE(policy, chain);
7062
7063 if (policy->cond_bound_interface) {
7064 ifnet_release(policy->cond_bound_interface);
7065 policy->cond_bound_interface = NULL;
7066 }
7067
7068 zfree(necp_ip_policy_zone, policy);
7069 return TRUE;
7070 }
7071
7072 return FALSE;
7073 }
7074
7075 static void
necp_kernel_ip_output_policies_dump_all(void)7076 necp_kernel_ip_output_policies_dump_all(void)
7077 {
7078 if (necp_debug) {
7079 struct necp_kernel_ip_output_policy *policy = NULL;
7080 int policy_i;
7081 int id_i;
7082 char result_string[MAX_RESULT_STRING_LEN];
7083 char proc_name_string[MAXCOMLEN + 1];
7084 memset(result_string, 0, MAX_RESULT_STRING_LEN);
7085 memset(proc_name_string, 0, MAXCOMLEN + 1);
7086
7087 NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
7088 NECPLOG0(LOG_DEBUG, "-----------\n");
7089 for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
7090 NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
7091 for (policy_i = 0; necp_kernel_ip_output_policies_map[id_i] != NULL && (necp_kernel_ip_output_policies_map[id_i])[policy_i] != NULL; policy_i++) {
7092 policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
7093 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
7094 NECPLOG(LOG_DEBUG, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d.%d\tMask: %llx\tResult: %s\n", policy_i, policy->id, proc_name_string, policy->session_order, policy->order, policy->suborder, policy->condition_mask, necp_get_result_description(result_string, policy->result, policy->result_parameter));
7095 }
7096 NECPLOG0(LOG_DEBUG, "-----------\n");
7097 }
7098 }
7099 }
7100
7101 static inline bool
necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy * upper_policy,struct necp_kernel_ip_output_policy * lower_policy)7102 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
7103 {
7104 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7105 if (upper_policy->session_order != lower_policy->session_order) {
7106 // A skip cannot override a policy of a different session
7107 return FALSE;
7108 } else {
7109 if (upper_policy->result_parameter.skip_policy_order == 0 ||
7110 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
7111 // This policy is beyond the skip
7112 return FALSE;
7113 } else {
7114 // This policy is inside the skip
7115 return TRUE;
7116 }
7117 }
7118 }
7119
7120 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
7121 return TRUE;
7122 }
7123
7124 static bool
necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy * policy,struct necp_kernel_ip_output_policy ** __indexable policy_array,int valid_indices)7125 necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy *policy, struct necp_kernel_ip_output_policy ** __indexable policy_array, int valid_indices)
7126 {
7127 bool can_skip = FALSE;
7128 u_int32_t highest_skip_session_order = 0;
7129 u_int32_t highest_skip_order = 0;
7130 int i;
7131 for (i = 0; i < valid_indices; i++) {
7132 struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
7133
7134 // For policies in a skip window, we can't mark conflicting policies as unnecessary
7135 if (can_skip) {
7136 if (highest_skip_session_order != compared_policy->session_order ||
7137 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
7138 // If we've moved on to the next session, or passed the skip window
7139 highest_skip_session_order = 0;
7140 highest_skip_order = 0;
7141 can_skip = FALSE;
7142 } else {
7143 // If this policy is also a skip, in can increase the skip window
7144 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7145 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
7146 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7147 }
7148 }
7149 continue;
7150 }
7151 }
7152
7153 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7154 // This policy is a skip. Set the skip window accordingly
7155 can_skip = TRUE;
7156 highest_skip_session_order = compared_policy->session_order;
7157 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7158 }
7159
7160 // The result of the compared policy must be able to block out this policy result
7161 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
7162 continue;
7163 }
7164
7165 // If new policy matches All Interfaces, compared policy must also
7166 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
7167 continue;
7168 }
7169
7170 // If new policy matches Local Networks, compared policy must also
7171 if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
7172 continue;
7173 }
7174
7175 // Default makes lower policies unnecessary always
7176 if (compared_policy->condition_mask == 0) {
7177 return TRUE;
7178 }
7179
7180 // Compared must be more general than policy, and include only conditions within policy
7181 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
7182 continue;
7183 }
7184
7185 // Negative conditions must match for the overlapping conditions
7186 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
7187 continue;
7188 }
7189
7190 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
7191 compared_policy->cond_policy_id != policy->cond_policy_id) {
7192 continue;
7193 }
7194
7195 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
7196 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
7197 continue;
7198 }
7199
7200 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
7201 compared_policy->cond_protocol != policy->cond_protocol) {
7202 continue;
7203 }
7204
7205 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7206 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7207 if (!necp_is_range_in_range(SA(&policy->cond_local_start), SA(&policy->cond_local_end), SA(&compared_policy->cond_local_start), SA(&compared_policy->cond_local_end))) {
7208 continue;
7209 }
7210 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7211 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
7212 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
7213 continue;
7214 }
7215 }
7216 }
7217
7218 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7219 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7220 if (!necp_is_range_in_range(SA(&policy->cond_remote_start), SA(&policy->cond_remote_end), SA(&compared_policy->cond_remote_start), SA(&compared_policy->cond_remote_end))) {
7221 continue;
7222 }
7223 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7224 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
7225 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
7226 continue;
7227 }
7228 }
7229 }
7230
7231 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
7232 compared_policy->cond_scheme_port != policy->cond_scheme_port) {
7233 continue;
7234 }
7235
7236 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
7237 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
7238 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
7239 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
7240 continue;
7241 }
7242
7243 return TRUE;
7244 }
7245
7246 return FALSE;
7247 }
7248
7249 static bool
necp_kernel_ip_output_policies_reprocess(void)7250 necp_kernel_ip_output_policies_reprocess(void)
7251 {
7252 int i;
7253 int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
7254 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7255
7256 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7257
7258 // Reset mask to 0
7259 necp_kernel_ip_output_policies_condition_mask = 0;
7260 necp_kernel_ip_output_policies_count = 0;
7261 necp_kernel_ip_output_policies_non_id_count = 0;
7262
7263 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7264 if (necp_kernel_ip_output_policies_map[i] != NULL) {
7265 kfree_type(struct necp_kernel_ip_output_policy *,
7266 necp_kernel_ip_output_policies_map_counts[i] + 1,
7267 necp_kernel_ip_output_policies_map[i]);
7268 necp_kernel_ip_output_policies_map[i] = NULL;
7269 }
7270
7271 // Init counts
7272 necp_kernel_ip_output_policies_map_counts[i] = 0;
7273 }
7274
7275 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7276 // Update mask
7277 necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
7278 necp_kernel_ip_output_policies_count++;
7279
7280 /* Update bucket counts:
7281 * Non-id and SKIP policies will be added to all buckets
7282 * Add local networks policy to all buckets for incoming IP
7283 */
7284 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7285 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7286 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7287 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7288 necp_kernel_ip_output_policies_map_counts[i]++;
7289 }
7290 }
7291 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
7292 necp_kernel_ip_output_policies_non_id_count++;
7293 } else {
7294 necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
7295 }
7296 }
7297
7298 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7299 if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
7300 // Allocate a NULL-terminated array of policy pointers for each bucket
7301 necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
7302 necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
7303 if (necp_kernel_ip_output_policies_map[i] == NULL) {
7304 goto fail;
7305 }
7306 }
7307 bucket_current_free_index[i] = 0;
7308 }
7309
7310 u_int32_t current_session_order = 0;
7311 u_int32_t current_session_last_non_skip_policy = 0;
7312
7313 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7314 // For each new session, find the last non-skip policy. We can
7315 // avoid adding any skip policies that don't actually skip over
7316 // any non-skip policies.
7317 if (current_session_order != kernel_policy->session_order) {
7318 current_session_order = kernel_policy->session_order;
7319 current_session_last_non_skip_policy = 0;
7320
7321 struct necp_kernel_ip_output_policy *inner_policy = NULL;
7322 LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
7323 if (inner_policy->session_order < current_session_order) {
7324 continue;
7325 }
7326 if (inner_policy->session_order > current_session_order) {
7327 break;
7328 }
7329 if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7330 continue;
7331 }
7332
7333 current_session_last_non_skip_policy = inner_policy->order;
7334 }
7335 }
7336
7337 if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7338 if (current_session_last_non_skip_policy == 0) {
7339 // No useful policies to skip over, don't add
7340 continue;
7341 }
7342 if (kernel_policy->order >= current_session_last_non_skip_policy) {
7343 // Skip policy is after the last useful policy, don't add
7344 continue;
7345 }
7346 }
7347
7348 // Insert pointers into map
7349 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7350 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7351 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7352 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7353 if (!necp_dedup_policies || !necp_kernel_ip_output_policy_is_unnecessary(kernel_policy, necp_kernel_ip_output_policies_map[i], bucket_current_free_index[i])) {
7354 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7355 bucket_current_free_index[i]++;
7356 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7357 }
7358 }
7359 } else {
7360 i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7361 if (!necp_dedup_policies || !necp_kernel_ip_output_policy_is_unnecessary(kernel_policy, necp_kernel_ip_output_policies_map[i], bucket_current_free_index[i])) {
7362 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7363 bucket_current_free_index[i]++;
7364 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7365 }
7366 }
7367 }
7368
7369 if (bucket_current_free_index[0] == 0) {
7370 // No non-id policies were actually added
7371 necp_kernel_ip_output_policies_non_id_count = 0;
7372
7373 // Also check if no policies at all were added
7374 bool policies_added = FALSE;
7375 for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7376 if (bucket_current_free_index[i] != 0) {
7377 policies_added = TRUE;
7378 break;
7379 }
7380 }
7381 if (!policies_added) {
7382 necp_kernel_ip_output_policies_condition_mask = 0;
7383 necp_kernel_ip_output_policies_count = 0;
7384 }
7385 }
7386
7387 necp_kernel_ip_output_policies_dump_all();
7388 return TRUE;
7389
7390 fail:
7391 // Free memory, reset mask to 0
7392 necp_kernel_ip_output_policies_condition_mask = 0;
7393 necp_kernel_ip_output_policies_count = 0;
7394 necp_kernel_ip_output_policies_non_id_count = 0;
7395 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7396 if (necp_kernel_ip_output_policies_map[i] != NULL) {
7397 kfree_type(struct necp_kernel_ip_output_policy *,
7398 necp_kernel_ip_output_policies_map_counts[i] + 1,
7399 necp_kernel_ip_output_policies_map[i]);
7400 necp_kernel_ip_output_policies_map[i] = NULL;
7401 }
7402 }
7403 return FALSE;
7404 }
7405
7406 // Outbound Policy Matching
7407 // ---------------------
7408 struct substring {
7409 size_t length;
7410 char * __sized_by(length) string;
7411 };
7412
7413 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7414 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7415 {
7416 struct substring sub = {};
7417 char * __indexable ptr = string;
7418 size_t len = string ? length : 0;
7419
7420 while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7421 ptr++;
7422 len--;
7423 }
7424
7425 while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7426 len--;
7427 }
7428
7429 sub.string = ptr;
7430 sub.length = len;
7431 return sub;
7432 }
7433
7434 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7435 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7436 {
7437 size_t trimmed_domain_length = 0;
7438 char *trimmed_domain = NULL;
7439 struct substring sub = necp_trim_dots_and_stars(string, length);
7440
7441 trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7442 trimmed_domain_length = sub.length + 1;
7443 if (trimmed_domain == NULL) {
7444 return NULL;
7445 }
7446
7447 strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7448 trimmed_domain[sub.length] = 0;
7449
7450 return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7451 }
7452
7453 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7454 necp_count_dots(char * __sized_by(length)string, size_t length)
7455 {
7456 int dot_count = 0;
7457 size_t i = 0;
7458
7459 for (i = 0; i < length; i++) {
7460 if (string[i] == '.') {
7461 dot_count++;
7462 }
7463 }
7464
7465 return dot_count;
7466 }
7467
7468 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7469 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7470 {
7471 if (parent.length <= suffix.length) {
7472 return FALSE;
7473 }
7474
7475 size_t length_difference = (parent.length - suffix.length);
7476
7477 if (require_dot_before_suffix) {
7478 if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7479 return FALSE;
7480 }
7481 }
7482
7483 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7484 return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7485 }
7486
7487 static bool
necp_hostname_matches_domain(struct substring hostname_substring,u_int8_t hostname_dot_count,char * domain __null_terminated,u_int8_t domain_dot_count)7488 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7489 {
7490 if (hostname_substring.string == NULL || domain == NULL) {
7491 return hostname_substring.string == domain;
7492 }
7493
7494 struct substring domain_substring;
7495 domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7496 domain_substring.length = strlen(domain);
7497
7498 if (hostname_dot_count == domain_dot_count) {
7499 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7500 if (hostname_substring.length == domain_substring.length &&
7501 strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7502 return TRUE;
7503 }
7504 } else if (domain_dot_count < hostname_dot_count) {
7505 if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7506 return TRUE;
7507 }
7508 }
7509
7510 return FALSE;
7511 }
7512
7513 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7514 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7515 {
7516 if (hostname_string == NULL ||
7517 domain_string == NULL) {
7518 return false;
7519 }
7520
7521 struct substring hostname_substring;
7522 hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7523 hostname_substring.length = strlen(hostname_string);
7524
7525 return necp_hostname_matches_domain(hostname_substring,
7526 necp_count_dots(hostname_substring.string, hostname_substring.length),
7527 domain_string,
7528 necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7529 }
7530
7531 #define NECP_MAX_STRING_LEN 1024
7532
7533 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7534 necp_copy_string(char * __sized_by(length)string, size_t length)
7535 {
7536 size_t copied_string_length = 0;
7537 char * __sized_by(copied_string_length) copied_string = NULL;
7538
7539 if (length > NECP_MAX_STRING_LEN) {
7540 return NULL;
7541 }
7542
7543 copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7544 copied_string_length = length + 1;
7545 if (copied_string == NULL) {
7546 return NULL;
7547 }
7548
7549 memcpy(copied_string, string, length);
7550 copied_string[length] = 0;
7551
7552 return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7553 }
7554
7555 static u_int32_t
necp_get_primary_direct_interface_index(void)7556 necp_get_primary_direct_interface_index(void)
7557 {
7558 u_int32_t interface_index = IFSCOPE_NONE;
7559
7560 ifnet_head_lock_shared();
7561 struct ifnet *ordered_interface = NULL;
7562 TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7563 const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7564 if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7565 functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7566 // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7567 interface_index = ordered_interface->if_index;
7568 break;
7569 }
7570 }
7571 ifnet_head_done();
7572
7573 return interface_index;
7574 }
7575
7576 static inline bool
necp_task_has_match_entitlement(task_t task)7577 necp_task_has_match_entitlement(task_t task)
7578 {
7579 return task != NULL &&
7580 (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7581 IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7582 }
7583
7584 // Loopback traffic from certain entitled process will be dropped
7585 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7586 necp_task_has_loopback_drop_entitlement(task_t task)
7587 {
7588 bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7589 if (drop) {
7590 necp_drop_loopback_count++;
7591 }
7592 return drop;
7593 }
7594
7595 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7596 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7597 {
7598 coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7599
7600 if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7601 // No parent, nothing to do
7602 return;
7603 }
7604
7605 task_t __single lead_task = coalition_get_leader(coal);
7606 if (lead_task != NULL) {
7607 info->is_entitled = necp_task_has_match_entitlement(lead_task);
7608 task_deallocate(lead_task);
7609 }
7610 }
7611
7612 // Some processes, due to particular entitlements, require using an NECP client to
7613 // access networking. Returns true if the result should be a Drop.
7614 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7615 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7616 {
7617 if (necp_is_platform_binary(proc)) {
7618 // This check is currently for the "on-demand-install-capable"
7619 // entitlement, which by definition cannot be a built-in platform
7620 // binary.
7621 return false;
7622 }
7623
7624 task_t __single task = proc_task(proc ? proc : current_proc());
7625
7626 if (!info->has_client &&
7627 task != NULL &&
7628 IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7629 // Drop connections that don't use NECP clients and have the
7630 // com.apple.developer.on-demand-install-capable entitlement.
7631 // This effectively restricts those processes to only using
7632 // an NECP-aware path for networking.
7633 return true;
7634 } else {
7635 return false;
7636 }
7637 }
7638
7639 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7640 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7641 {
7642 if (!necp_restrict_multicast || proc == NULL) {
7643 return false;
7644 }
7645
7646 // Check for multicast/broadcast here
7647 if (info->remote_addr.sa.sa_family == AF_INET) {
7648 if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7649 info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7650 return false;
7651 }
7652 } else if (info->remote_addr.sa.sa_family == AF_INET6) {
7653 if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7654 return false;
7655 }
7656 } else {
7657 // Not IPv4/IPv6
7658 return false;
7659 }
7660
7661 if (necp_is_platform_binary(proc)) {
7662 return false;
7663 }
7664
7665 const uint32_t platform = proc_platform(proc);
7666 const uint32_t sdk = proc_sdk(proc);
7667
7668 // Enforce for iOS, linked on or after version 14
7669 // If the caller set `check_minor_version`, only enforce starting at 14.5
7670 if ((platform != PLATFORM_IOS ||
7671 sdk == 0 ||
7672 (sdk >> 16) < 14 ||
7673 (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7674 return false;
7675 }
7676
7677 // Allow entitled processes to use multicast
7678 task_t __single task = proc_task(proc);
7679 if (task != NULL &&
7680 IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7681 return false;
7682 }
7683
7684 const uint32_t min_sdk = proc_min_sdk(proc);
7685 NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7686
7687 return true;
7688 }
7689
7690 #define NECP_KERNEL_ADDRESS_TYPE_CONDITIONS (NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_SCHEME_PORT)
7691 static void
necp_application_fillout_info_locked(task_t task,uuid_t application_uuid,uuid_t real_application_uuid,uuid_t responsible_application_uuid,char * account __null_terminated,char * domain __null_terminated,char * url __null_terminated,pid_t pid,int32_t pid_version,uid_t uid,uid_t real_uid,u_int16_t protocol,u_int32_t bound_interface_index,u_int32_t traffic_class,union necp_sockaddr_union * local_addr,union necp_sockaddr_union * remote_addr,u_int16_t local_port,u_int16_t remote_port,bool has_client,bool has_system_signed_result,proc_t real_proc,proc_t proc,proc_t responsible_proc,u_int32_t drop_order,u_int32_t client_flags,u_int16_t scheme_port,struct necp_socket_info * info,bool is_loopback,bool is_delegated)7692 necp_application_fillout_info_locked(task_t task, uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account __null_terminated, char *domain __null_terminated, char *url __null_terminated, pid_t pid, int32_t pid_version, uid_t uid, uid_t real_uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, union necp_sockaddr_union *local_addr, union necp_sockaddr_union *remote_addr, u_int16_t local_port, u_int16_t remote_port, bool has_client, bool has_system_signed_result, proc_t real_proc, proc_t proc, proc_t responsible_proc, u_int32_t drop_order, u_int32_t client_flags, u_int16_t scheme_port, struct necp_socket_info *info, bool is_loopback, bool is_delegated)
7693 {
7694 memset(info, 0, sizeof(struct necp_socket_info));
7695
7696 info->pid = pid;
7697 info->pid_version = pid_version;
7698 info->uid = uid;
7699 info->real_uid = real_uid;
7700 info->protocol = protocol;
7701 info->bound_interface_index = bound_interface_index;
7702 info->traffic_class = traffic_class;
7703 info->has_client = has_client;
7704 info->has_system_signed_result = has_system_signed_result;
7705 info->drop_order = drop_order;
7706 info->client_flags = client_flags;
7707 info->is_loopback = is_loopback;
7708 info->is_delegated = is_delegated;
7709
7710 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7711 info->bound_interface_index != IFSCOPE_NONE) {
7712 ifnet_head_lock_shared();
7713 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7714 if (interface != NULL) {
7715 info->bound_interface_flags = interface->if_flags;
7716 info->bound_interface_eflags = interface->if_eflags;
7717 info->bound_interface_xflags = interface->if_xflags;
7718 }
7719 ifnet_head_done();
7720 }
7721
7722 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7723 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7724 if (existing_mapping) {
7725 info->application_id = existing_mapping->id;
7726 }
7727 }
7728
7729 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7730 if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7731 info->real_application_id = info->application_id;
7732 } else {
7733 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7734 if (existing_mapping) {
7735 info->real_application_id = existing_mapping->id;
7736 }
7737 }
7738 }
7739
7740 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7741 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7742 if (existing_mapping != NULL) {
7743 info->real_application_id = info->application_id;
7744 info->application_id = existing_mapping->id;
7745 info->used_responsible_pid = true;
7746 }
7747 }
7748
7749 if (info->used_responsible_pid) {
7750 proc = responsible_proc;
7751 }
7752
7753 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7754 info->is_entitled = necp_task_has_match_entitlement(task);
7755 if (!info->is_entitled) {
7756 // Task does not have entitlement, check the parent task
7757 necp_get_parent_is_entitled(task, info);
7758 }
7759 }
7760
7761 if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7762 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7763 if (necp_is_platform_binary(proc)) {
7764 info->is_platform_binary = true;
7765 } else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7766 info->is_platform_binary = true;
7767 info->used_responsible_pid = true;
7768 } else {
7769 info->is_platform_binary = false;
7770 }
7771 }
7772
7773 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7774 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7775 }
7776
7777 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7778 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7779 if (existing_mapping) {
7780 info->account_id = existing_mapping->id;
7781 }
7782 }
7783
7784 if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7785 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7786 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7787 info->domain = domain;
7788 }
7789
7790 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7791 info->url = url;
7792 }
7793
7794 if ((necp_data_tracing_level && necp_data_tracing_port) ||
7795 necp_restrict_multicast ||
7796 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7797 if (local_addr && local_addr->sa.sa_len > 0) {
7798 SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7799 if (local_port != 0) {
7800 info->local_addr.sin6.sin6_port = local_port;
7801 }
7802 } else {
7803 if (remote_addr && remote_addr->sa.sa_len > 0) {
7804 info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7805 info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7806 } else {
7807 info->local_addr.sin6.sin6_family = AF_INET6;
7808 info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7809 }
7810 if (local_port != 0) {
7811 info->local_addr.sin6.sin6_port = local_port;
7812 }
7813 }
7814 if (remote_addr && remote_addr->sa.sa_len > 0) {
7815 SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7816 if (remote_port != 0) {
7817 info->remote_addr.sin6.sin6_port = remote_port;
7818 }
7819 } else if (remote_port != 0) {
7820 info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7821 info->remote_addr.sin6.sin6_family = AF_INET6;
7822 info->remote_addr.sin6.sin6_port = remote_port;
7823 }
7824 }
7825
7826 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7827 info->scheme_port = scheme_port;
7828 }
7829 }
7830
7831 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7832 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7833 {
7834 struct kev_netpolicy_ifdenied ev_ifdenied;
7835
7836 bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7837
7838 ev_ifdenied.ev_data.epid = pid;
7839 uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7840 ev_ifdenied.ev_if_functional_type = if_functional_type;
7841
7842 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7843 }
7844
7845 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7846 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7847 {
7848 struct kev_netpolicy_netdenied ev_netdenied = {};
7849
7850 bzero(&ev_netdenied, sizeof(ev_netdenied));
7851
7852 ev_netdenied.ev_data.epid = pid;
7853 uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7854 ev_netdenied.ev_network_type = network_type;
7855
7856 netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7857 }
7858
7859 extern char *proc_name_address(void *p);
7860
7861 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7862 if (!has_checked_delegation_entitlement) { \
7863 has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7864 has_checked_delegation_entitlement = TRUE; \
7865 } \
7866 if (!has_delegation_entitlement) { \
7867 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7868 proc_name_address(_p), proc_pid(_p), _d); \
7869 break; \
7870 }
7871
7872 int
necp_application_find_policy_match_internal(proc_t proc,u_int8_t * __sized_by (parameters_size)parameters,u_int32_t parameters_size,struct necp_aggregate_result * returned_result,u_int32_t * flags,u_int32_t * reason,u_int required_interface_index,const union necp_sockaddr_union * override_local_addr,const union necp_sockaddr_union * override_remote_addr,struct necp_client_endpoint * returned_v4_gateway,struct necp_client_endpoint * returned_v6_gateway,struct rtentry ** returned_route,bool ignore_address,bool has_client,uuid_t * returned_override_euuid)7873 necp_application_find_policy_match_internal(proc_t proc,
7874 u_int8_t * __sized_by(parameters_size)parameters,
7875 u_int32_t parameters_size,
7876 struct necp_aggregate_result *returned_result,
7877 u_int32_t *flags,
7878 u_int32_t *reason,
7879 u_int required_interface_index,
7880 const union necp_sockaddr_union *override_local_addr,
7881 const union necp_sockaddr_union *override_remote_addr,
7882 struct necp_client_endpoint *returned_v4_gateway,
7883 struct necp_client_endpoint *returned_v6_gateway,
7884 struct rtentry **returned_route, bool ignore_address,
7885 bool has_client,
7886 uuid_t *returned_override_euuid)
7887 {
7888 int error = 0;
7889 size_t offset = 0;
7890
7891 struct necp_kernel_socket_policy *matched_policy = NULL;
7892 struct necp_socket_info info = {};
7893 necp_kernel_policy_filter filter_control_unit = 0;
7894 necp_kernel_policy_result service_action = 0;
7895 necp_kernel_policy_service service = { 0, 0 };
7896
7897 u_int16_t protocol = 0;
7898 u_int32_t bound_interface_index = required_interface_index;
7899 u_int32_t traffic_class = 0;
7900 u_int32_t client_flags = 0;
7901 u_int16_t scheme_port = 0;
7902 union necp_sockaddr_union local_addr;
7903 union necp_sockaddr_union remote_addr;
7904 bool no_remote_addr = FALSE;
7905 u_int8_t remote_family = 0;
7906 bool no_local_addr = FALSE;
7907 u_int16_t local_port = 0;
7908 u_int16_t remote_port = 0;
7909 u_int32_t remote_endpoint_type = 0;
7910 bool remote_address_is_empty = false;
7911 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7912 bool is_delegated = false;
7913
7914 if (override_local_addr) {
7915 memcpy(&local_addr, override_local_addr, sizeof(local_addr));
7916 } else {
7917 memset(&local_addr, 0, sizeof(local_addr));
7918 }
7919 if (override_remote_addr) {
7920 memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
7921 } else {
7922 memset(&remote_addr, 0, sizeof(remote_addr));
7923 }
7924
7925 // Initialize UID, PID, and UUIDs to the current process
7926 uid_t uid = 0;
7927 uid_t real_uid = 0;
7928 kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
7929 if (cred != NULL) {
7930 uid = kauth_cred_getuid(cred);
7931 real_uid = uid;
7932 }
7933 task_t __single task = proc_task(proc);
7934 pid_t pid = proc_pid(proc);
7935 int32_t pid_version = proc_pidversion(proc);
7936 uuid_t application_uuid;
7937 uuid_clear(application_uuid);
7938 uuid_t real_application_uuid;
7939 uuid_clear(real_application_uuid);
7940 proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
7941 uuid_copy(application_uuid, real_application_uuid);
7942 uuid_t responsible_application_uuid;
7943 uuid_clear(responsible_application_uuid);
7944
7945 char *domain __null_terminated = NULL;
7946 char *url __null_terminated = NULL;
7947 char *account __null_terminated = NULL;
7948
7949 #define NECP_MAX_REQUIRED_AGENTS 16
7950 u_int32_t num_required_agent_types = 0;
7951 struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
7952 memset(&required_agent_types, 0, sizeof(required_agent_types));
7953
7954 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
7955 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
7956 memset(&netagent_ids, 0, sizeof(netagent_ids));
7957 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
7958 int netagent_cursor;
7959
7960 bool has_checked_delegation_entitlement = false;
7961 bool has_delegation_entitlement = false;
7962 bool has_system_signed_result = false;
7963
7964 proc_t responsible_proc = PROC_NULL;
7965 proc_t effective_proc = proc;
7966 bool release_eproc = false;
7967 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
7968
7969 u_int32_t flow_divert_aggregate_unit = 0;
7970
7971 if (returned_result == NULL) {
7972 if (cred != NULL) {
7973 kauth_cred_unref(&cred);
7974 }
7975 return EINVAL;
7976 }
7977
7978 if (returned_v4_gateway != NULL) {
7979 memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
7980 }
7981
7982 if (returned_v6_gateway != NULL) {
7983 memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
7984 }
7985
7986 if (returned_override_euuid != NULL) {
7987 uuid_clear(*returned_override_euuid);
7988 }
7989
7990 memset(returned_result, 0, sizeof(struct necp_aggregate_result));
7991
7992 u_int32_t drop_order = necp_process_drop_order(cred);
7993
7994 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
7995
7996 lck_rw_lock_shared(&necp_kernel_policy_lock);
7997 if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
7998 if (necp_drop_all_order > 0 || drop_order > 0) {
7999 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8000 lck_rw_done(&necp_kernel_policy_lock);
8001 if (cred != NULL) {
8002 kauth_cred_unref(&cred);
8003 }
8004 return 0;
8005 }
8006 }
8007 lck_rw_done(&necp_kernel_policy_lock);
8008
8009 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
8010 u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
8011 u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
8012
8013 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
8014 // If the length is larger than what can fit in the remaining parameters size, bail
8015 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
8016 break;
8017 }
8018
8019 if (length > 0) {
8020 u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
8021 if (value != NULL) {
8022 switch (type) {
8023 case NECP_CLIENT_PARAMETER_APPLICATION: {
8024 if (length >= sizeof(uuid_t)) {
8025 if (uuid_compare(application_uuid, value) == 0) {
8026 // No delegation
8027 break;
8028 }
8029
8030 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
8031
8032 is_delegated = true;
8033 uuid_copy(application_uuid, value);
8034 }
8035 break;
8036 }
8037 case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
8038 if (length >= sizeof(uuid_t)) {
8039 if (uuid_compare(real_application_uuid, value) == 0) {
8040 // No delegation
8041 break;
8042 }
8043
8044 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
8045
8046 is_delegated = true;
8047 uuid_copy(real_application_uuid, value);
8048 }
8049 break;
8050 }
8051 case NECP_CLIENT_PARAMETER_PID: {
8052 if (length >= sizeof(pid_t)) {
8053 if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
8054 // No delegation
8055 break;
8056 }
8057
8058 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
8059
8060 is_delegated = true;
8061 memcpy(&pid, value, sizeof(pid_t));
8062 }
8063 break;
8064 }
8065 case NECP_CLIENT_PARAMETER_UID: {
8066 if (length >= sizeof(uid_t)) {
8067 if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
8068 // No delegation
8069 break;
8070 }
8071
8072 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
8073
8074 is_delegated = true;
8075 memcpy(&uid, value, sizeof(uid_t));
8076 }
8077 break;
8078 }
8079 case NECP_CLIENT_PARAMETER_DOMAIN: {
8080 char *ptr = (char *)value;
8081 ptr[length - 1] = 0;
8082 domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8083 break;
8084 }
8085 case NECP_CLIENT_PARAMETER_URL: {
8086 char *ptr = (char *)value;
8087 ptr[length - 1] = 0;
8088 url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8089 break;
8090 }
8091 case NECP_CLIENT_PARAMETER_ACCOUNT: {
8092 char *ptr = (char *)value;
8093 ptr[length - 1] = 0;
8094 account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8095 break;
8096 }
8097 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
8098 if (length >= sizeof(u_int32_t)) {
8099 memcpy(&traffic_class, value, sizeof(u_int32_t));
8100 }
8101 break;
8102 }
8103 case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
8104 if (length >= sizeof(u_int16_t)) {
8105 memcpy(&protocol, value, sizeof(u_int16_t));
8106 } else if (length >= sizeof(u_int8_t)) {
8107 memcpy(&protocol, value, sizeof(u_int8_t));
8108 }
8109 break;
8110 }
8111 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
8112 if (length <= IFXNAMSIZ && length > 0) {
8113 ifnet_t __single bound_interface = NULL;
8114 char interface_name[IFXNAMSIZ];
8115 memcpy(interface_name, value, length);
8116 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
8117 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
8118 bound_interface_index = bound_interface->if_index;
8119 ifnet_release(bound_interface);
8120 }
8121 }
8122 break;
8123 }
8124 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
8125 if (ignore_address || override_local_addr) {
8126 break;
8127 }
8128
8129 if (length >= sizeof(struct necp_policy_condition_addr)) {
8130 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8131 if (necp_address_is_valid(&address_struct->address.sa)) {
8132 memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
8133 }
8134 }
8135 break;
8136 }
8137 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
8138 if (ignore_address || override_remote_addr) {
8139 break;
8140 }
8141
8142 if (length >= sizeof(struct necp_policy_condition_addr)) {
8143 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8144 if (necp_address_is_valid(&address_struct->address.sa)) {
8145 memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
8146 }
8147 }
8148 break;
8149 }
8150 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
8151 if (ignore_address || override_local_addr) {
8152 break;
8153 }
8154
8155 if (length >= sizeof(struct necp_client_endpoint)) {
8156 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8157 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
8158 endpoint->u.endpoint.endpoint_port != 0) {
8159 // Save port
8160 local_port = endpoint->u.endpoint.endpoint_port;
8161 }
8162 }
8163 break;
8164 }
8165 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
8166 if (ignore_address || override_remote_addr) {
8167 break;
8168 }
8169
8170 if (length >= sizeof(struct necp_client_endpoint)) {
8171 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8172 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
8173 remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
8174 if (endpoint->u.endpoint.endpoint_port != 0) {
8175 // Save port
8176 remote_port = endpoint->u.endpoint.endpoint_port;
8177 }
8178 } else if (necp_addr_is_empty(&endpoint->u.sa)) {
8179 remote_address_is_empty = true;
8180 }
8181 }
8182 break;
8183 }
8184 case NECP_CLIENT_PARAMETER_FLAGS: {
8185 if (length >= sizeof(client_flags)) {
8186 memcpy(&client_flags, value, sizeof(client_flags));
8187 }
8188 break;
8189 }
8190 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
8191 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
8192 if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8193 break;
8194 }
8195 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
8196 memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
8197 num_required_agent_types++;
8198 }
8199 break;
8200 }
8201 case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
8202 if (length >= sizeof(scheme_port)) {
8203 memcpy(&scheme_port, value, sizeof(scheme_port));
8204 }
8205 break;
8206 }
8207 case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
8208 has_system_signed_result = true;
8209 struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
8210 if (length >= sizeof(struct necp_client_validatable)) {
8211 // Check for system-signed sign_type values
8212 if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
8213 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
8214 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
8215 has_system_signed_result = true;
8216 }
8217 }
8218 break;
8219 }
8220 default: {
8221 break;
8222 }
8223 }
8224 }
8225 }
8226
8227 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
8228 }
8229
8230 // Check for loopback exception
8231 if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
8232 if (necp_task_has_loopback_drop_entitlement(task)) {
8233 // Disallow certain entitled processes to send loopback traffic
8234 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8235 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8236 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8237 if (cred != NULL) {
8238 kauth_cred_unref(&cred);
8239 }
8240 return 0;
8241 }
8242 if (necp_pass_loopback > 0) {
8243 bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
8244 }
8245 } else if (bound_interface_index != IFSCOPE_NONE) {
8246 // Check for inter-process exception
8247 struct sockaddr *dst = SA(&remote_addr.sa);
8248 if (dst->sa_family == AF_INET6) {
8249 struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
8250 if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
8251 ifnet_head_lock_shared();
8252 ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
8253 if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
8254 bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
8255 }
8256 ifnet_head_done();
8257 }
8258 }
8259 }
8260
8261 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
8262 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8263 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8264 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8265 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
8266 returned_result->routed_interface_index = lo_ifp->if_index;
8267 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8268 } else {
8269 returned_result->routed_interface_index = bound_interface_index;
8270 }
8271 if (cred != NULL) {
8272 kauth_cred_unref(&cred);
8273 }
8274 return 0;
8275 }
8276
8277 if (drop_order != 0) {
8278 if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
8279 client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
8280 ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
8281 // Allow listeners, inbound connections without remote addresses, and
8282 // application service connections to bypass the unentitled drop order,
8283 // to allow them to connect to application services (not directly over
8284 // physical networking interfaces)
8285 drop_order = 0;
8286 }
8287 }
8288
8289 if (proc_pid(effective_proc) != pid) {
8290 proc_t found_proc = proc_find(pid);
8291 if (found_proc != PROC_NULL) {
8292 effective_proc = found_proc;
8293 pid_version = proc_pidversion(effective_proc);
8294 release_eproc = true;
8295 }
8296 }
8297 #if defined(XNU_TARGET_OS_OSX)
8298 if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
8299 proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
8300 responsible_proc = proc_find(effective_proc->p_responsible_pid);
8301 }
8302 #endif /* defined(XNU_TARGET_OS_OSX) */
8303
8304 // Lock
8305 lck_rw_lock_shared(&necp_kernel_policy_lock);
8306
8307 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
8308 size_t route_rule_id_array_count = 0;
8309 necp_application_fillout_info_locked(task, application_uuid, real_application_uuid, responsible_application_uuid, account, domain, url, pid, pid_version, uid, real_uid, protocol, bound_interface_index, traffic_class, &local_addr, &remote_addr, local_port, remote_port, has_client, has_system_signed_result, proc, effective_proc, responsible_proc, drop_order, client_flags, scheme_port, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), is_delegated);
8310
8311 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
8312 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
8313
8314 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
8315 matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
8316 &info,
8317 &filter_control_unit,
8318 route_rule_id_array,
8319 &route_rule_id_array_count,
8320 MAX_AGGREGATE_ROUTE_RULES,
8321 &service_action,
8322 &service,
8323 netagent_ids,
8324 NECP_MAX_NETAGENTS,
8325 netagent_use_flags,
8326 NECP_MAX_NETAGENTS,
8327 required_agent_types,
8328 num_required_agent_types,
8329 info.used_responsible_pid ? responsible_proc : effective_proc,
8330 0,
8331 &skip_policy_id,
8332 NULL,
8333 &drop_dest_policy_result,
8334 &drop_all_bypass,
8335 &flow_divert_aggregate_unit,
8336 NULL,
8337 debug);
8338
8339 // Check for loopback exception again after the policy match
8340 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
8341 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
8342 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
8343 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8344 returned_result->filter_control_unit = 0;
8345 } else {
8346 returned_result->filter_control_unit = filter_control_unit;
8347 }
8348
8349 if (flow_divert_aggregate_unit > 0) {
8350 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8351 }
8352
8353 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8354 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8355 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8356 returned_result->routed_interface_index = lo_ifp->if_index;
8357 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8358 error = 0;
8359 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8360 goto done;
8361 }
8362
8363 if (matched_policy) {
8364 returned_result->policy_id = matched_policy->id;
8365 returned_result->skip_policy_id = skip_policy_id;
8366 returned_result->routing_result = matched_policy->result;
8367 memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8368 if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8369 uuid_copy(*returned_override_euuid, responsible_application_uuid);
8370 }
8371 } else {
8372 bool drop_all = false;
8373 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8374 // Mark socket as a drop if drop_all is set
8375 drop_all = true;
8376 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8377 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8378 }
8379 }
8380 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8381 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8382 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8383 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8384 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8385 } else {
8386 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8387 returned_result->skip_policy_id = skip_policy_id;
8388 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8389 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8390 }
8391 }
8392 if (necp_check_missing_client_drop(proc, &info) ||
8393 necp_check_restricted_multicast_drop(proc, &info, false)) {
8394 // Mark as drop
8395 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8396 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8397 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8398 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8399 }
8400 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8401 returned_result->filter_control_unit = 0;
8402 } else {
8403 returned_result->filter_control_unit = filter_control_unit;
8404 }
8405
8406 if (flow_divert_aggregate_unit > 0) {
8407 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8408 }
8409
8410 returned_result->service_action = service_action;
8411
8412 // Fetch service registration
8413 if (service.identifier != 0) {
8414 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
8415 if (mapping != NULL) {
8416 struct necp_service_registration *service_registration = NULL;
8417 uuid_copy(returned_result->service_uuid, mapping->uuid);
8418 returned_result->service_data = service.data;
8419 if (service.identifier == NECP_NULL_SERVICE_ID) {
8420 // NULL service is always 'registered'
8421 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8422 } else {
8423 LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
8424 if (service.identifier == service_registration->service_id) {
8425 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8426 break;
8427 }
8428 }
8429 }
8430 }
8431 }
8432
8433 // Handle netagents
8434 size_t netagent_i = 0;
8435 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8436 struct necp_uuid_id_mapping *mapping = NULL;
8437 u_int32_t netagent_id = netagent_ids[netagent_cursor];
8438 if (netagent_id == 0) {
8439 continue;
8440 }
8441 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8442 if (mapping != NULL) {
8443 uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8444 returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8445 netagent_i++;
8446 }
8447
8448 // If the flags say to remove, clear the local copy
8449 if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8450 netagent_ids[netagent_cursor] = 0;
8451 }
8452 }
8453
8454 // Do routing evaluation
8455 u_int output_bound_interface = bound_interface_index;
8456 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8457 output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8458 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8459 output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8460 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8461 output_bound_interface = necp_get_primary_direct_interface_index();
8462 if (output_bound_interface == IFSCOPE_NONE) {
8463 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8464 } else {
8465 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8466 returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8467 }
8468 }
8469
8470 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8471 returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8472 if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8473 // Trigger the event that we dropped due to a local network policy
8474 #if defined(XNU_TARGET_OS_OSX)
8475 bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8476 necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8477 should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8478 NETPOLICY_NETWORKTYPE_LOCAL);
8479 #else
8480 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8481 #endif
8482 }
8483 if (reason != NULL) {
8484 *reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8485 }
8486 }
8487
8488 if (local_addr.sa.sa_len == 0 ||
8489 (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8490 (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8491 no_local_addr = TRUE;
8492 }
8493
8494 if (remote_addr.sa.sa_len == 0 ||
8495 (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8496 (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8497 no_remote_addr = TRUE;
8498 remote_family = remote_addr.sa.sa_family;
8499 }
8500
8501 returned_result->routed_interface_index = 0;
8502 struct rtentry *rt = NULL;
8503 if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8504 // Treat the output bound interface as the routed interface for local address
8505 // validation later.
8506 returned_result->routed_interface_index = output_bound_interface;
8507 } else {
8508 if (no_remote_addr) {
8509 memset(&remote_addr, 0, sizeof(remote_addr));
8510 if (remote_family == AF_INET6) {
8511 // Reset address to ::
8512 remote_addr.sa.sa_family = AF_INET6;
8513 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8514 } else {
8515 // Reset address to 0.0.0.0
8516 remote_addr.sa.sa_family = AF_INET;
8517 remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8518 }
8519 }
8520
8521 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8522 output_bound_interface);
8523
8524 if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8525 IS_INTF_CLAT46(rt->rt_ifp)) {
8526 rtfree(rt);
8527 rt = NULL;
8528 returned_result->routed_interface_index = 0;
8529 }
8530
8531 if (no_remote_addr && remote_family == AF_UNSPEC &&
8532 (rt == NULL || rt->rt_ifp == NULL)) {
8533 // Route lookup for default IPv4 failed, try IPv6
8534
8535 // Cleanup old route if necessary
8536 if (rt != NULL) {
8537 rtfree(rt);
8538 rt = NULL;
8539 }
8540
8541 // Reset address to ::
8542 memset(&remote_addr, 0, sizeof(remote_addr));
8543 remote_addr.sa.sa_family = AF_INET6;
8544 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8545
8546 // Get route
8547 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8548 output_bound_interface);
8549 }
8550
8551 if (rt != NULL &&
8552 rt->rt_ifp != NULL) {
8553 returned_result->routed_interface_index = rt->rt_ifp->if_index;
8554 /*
8555 * For local addresses, we allow the interface scope to be
8556 * either the loopback interface or the interface hosting the
8557 * local address.
8558 */
8559 if (bound_interface_index != IFSCOPE_NONE &&
8560 rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8561 (output_bound_interface == lo_ifp->if_index ||
8562 rt->rt_ifp->if_index == lo_ifp->if_index ||
8563 rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8564 struct sockaddr_storage dst;
8565 unsigned int ifscope = bound_interface_index;
8566
8567 /*
8568 * Transform dst into the internal routing table form
8569 */
8570 (void) sa_copy(SA(&remote_addr),
8571 &dst, &ifscope);
8572
8573 if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8574 rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8575 returned_result->routed_interface_index =
8576 bound_interface_index;
8577 }
8578 }
8579 }
8580 }
8581
8582 if (returned_result->routed_interface_index != 0 &&
8583 returned_result->routed_interface_index != lo_ifp->if_index && // Loopback can accept any local address
8584 !no_local_addr) {
8585 // Transform local_addr into the ifaddr form
8586 // IPv6 Scope IDs are always embedded in the ifaddr list
8587 struct sockaddr_storage local_address_sanitized;
8588 u_int ifscope = IFSCOPE_NONE;
8589 (void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8590 SIN(&local_address_sanitized)->sin_port = 0;
8591 if (local_address_sanitized.ss_family == AF_INET6) {
8592 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8593 SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8594 }
8595 }
8596
8597 // Validate local address on routed interface
8598 struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8599 if (ifa == NULL) {
8600 // Interface address not found, reject route
8601 returned_result->routed_interface_index = 0;
8602 if (rt != NULL) {
8603 rtfree(rt);
8604 rt = NULL;
8605 }
8606 } else {
8607 ifaddr_release(ifa);
8608 ifa = NULL;
8609 }
8610 }
8611
8612 if (flags != NULL) {
8613 #if SKYWALK
8614 if (kernel_is_macos_or_server()) {
8615 enum net_filter_event_subsystems filters = net_filter_event_get_state();
8616
8617 if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8618 *flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8619 }
8620 if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8621 *flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8622 }
8623 if (filters & NET_FILTER_EVENT_ALF) {
8624 *flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8625 }
8626 if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8627 *flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8628 }
8629 }
8630 #endif /* SKYWALK */
8631 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8632 // Check for local/direct
8633 bool is_local = FALSE;
8634 if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8635 is_local = TRUE;
8636 } else if (returned_result->routed_interface_index != 0 &&
8637 !no_remote_addr) {
8638 // Clean up the address before comparison with interface addresses
8639
8640 // Transform remote_addr into the ifaddr form
8641 // IPv6 Scope IDs are always embedded in the ifaddr list
8642 struct sockaddr_storage remote_address_sanitized;
8643 u_int ifscope = IFSCOPE_NONE;
8644 (void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8645 SIN(&remote_address_sanitized)->sin_port = 0;
8646 if (remote_address_sanitized.ss_family == AF_INET6) {
8647 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8648 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8649 }
8650 }
8651
8652 // Check if remote address is an interface address
8653 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8654 if (ifa != NULL && ifa->ifa_ifp != NULL) {
8655 u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8656 if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8657 if_index_for_remote_addr == lo_ifp->if_index) {
8658 is_local = TRUE;
8659 }
8660 }
8661 if (ifa != NULL) {
8662 ifaddr_release(ifa);
8663 ifa = NULL;
8664 }
8665 }
8666
8667 if (is_local) {
8668 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8669 } else if (rt != NULL) {
8670 if (rt->rt_flags & RTF_GLOBAL) {
8671 *flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8672 } else if (!(rt->rt_flags & RTF_GATEWAY) &&
8673 (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8674 // Route is directly accessible
8675 *flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8676 }
8677 }
8678
8679 if (rt != NULL &&
8680 rt->rt_ifp != NULL) {
8681 // Check probe status
8682 if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8683 *flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8684 }
8685
8686 if (if_link_heuristics_enabled(rt->rt_ifp)) {
8687 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_HEURISTICS;
8688 }
8689
8690 if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8691 struct if_cellular_status_v1 *ifsr;
8692
8693 ifnet_lock_shared(rt->rt_ifp);
8694 lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8695
8696 if (rt->rt_ifp->if_link_status != NULL) {
8697 ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8698
8699 if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8700 if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8701 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8702 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8703 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8704 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8705 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8706 }
8707 }
8708 }
8709 lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8710 ifnet_lock_done(rt->rt_ifp);
8711 }
8712
8713 // Check link quality
8714 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8715 (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8716 rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8717 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8718 }
8719
8720 // Check QoS marking (fastlane)
8721 for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8722 if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8723 *flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8724 // If the route can use QoS markings, stop iterating route rules
8725 break;
8726 }
8727 }
8728
8729 if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8730 *flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8731 }
8732
8733 if (traffic_class == SO_TC_BK_SYS) {
8734 // Block BK_SYS traffic if interface is throttled
8735 u_int32_t throttle_level = 0;
8736 if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8737 if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8738 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8739 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8740 }
8741 }
8742 }
8743 }
8744 }
8745
8746 u_int interface_to_check = returned_result->routed_interface_index;
8747 if (interface_to_check == 0) {
8748 interface_to_check = output_bound_interface;
8749 }
8750 union necp_sockaddr_union default_address;
8751 struct rtentry *v4Route = NULL;
8752 struct rtentry *v6Route = NULL;
8753
8754 memset(&default_address, 0, sizeof(default_address));
8755
8756 // Reset address to 0.0.0.0
8757 default_address.sa.sa_family = AF_INET;
8758 default_address.sa.sa_len = sizeof(struct sockaddr_in);
8759 v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8760 returned_result->routed_interface_index);
8761
8762 // Reset address to ::
8763 default_address.sa.sa_family = AF_INET6;
8764 default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8765 v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8766 returned_result->routed_interface_index);
8767
8768 if (v4Route != NULL) {
8769 if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8770 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8771 }
8772 if (returned_v4_gateway != NULL &&
8773 v4Route->rt_gateway != NULL &&
8774 v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8775 memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8776 memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8777 }
8778 rtfree(v4Route);
8779 v4Route = NULL;
8780 }
8781
8782 if (v6Route != NULL) {
8783 if (v6Route->rt_ifp != NULL) {
8784 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8785
8786 if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8787 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8788 }
8789 }
8790 if (returned_v6_gateway != NULL &&
8791 v6Route->rt_gateway != NULL &&
8792 v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8793 SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8794 }
8795 rtfree(v6Route);
8796 v6Route = NULL;
8797 }
8798 }
8799
8800 // Take two passes through the rule list: first for rules that don't match based on agents,
8801 // second for rules that match based on agents. Since rules can modify the agent list itself,
8802 // this makes the logic more deterministic. This allows a non-agent matching rule to remove
8803 // an agent before it is used for matching later.
8804 size_t route_rule_index = 0;
8805 bool second_pass = false;
8806 while (route_rule_index < route_rule_id_array_count) {
8807 bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8808 if (rule_matches_agents != second_pass) {
8809 // Process rules that match based on agents only in the second pass
8810 route_rule_index++;
8811 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8812 route_rule_index = 0;
8813 second_pass = true;
8814 }
8815 continue;
8816 }
8817
8818 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8819 bool route_is_allowed = necp_route_is_allowed(rt, NULL, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &interface_type_denied);
8820 if (!route_is_allowed) {
8821 // If the route is blocked, treat the lookup as a drop
8822 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8823 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8824
8825 if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8826 if (reason != NULL) {
8827 if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8828 *reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8829 } else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8830 *reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8831 }
8832 }
8833 necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8834 }
8835 // If the route gets denied, stop matching rules
8836 break;
8837 }
8838
8839 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8840 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8841 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8842 route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8843 if (flow_divert_control_unit != 0) {
8844 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8845 returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8846 }
8847 if (flow_divert_aggregate_unit != 0) {
8848 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8849 }
8850 }
8851
8852 // Check if there is a route rule that adds or removes an agent
8853 bool remove = false;
8854 u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8855 if (netagent_id != 0) {
8856 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8857 if (mapping != NULL) {
8858 bool agent_already_present = false;
8859 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8860 if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8861 // Found the agent already present
8862 agent_already_present = true;
8863 if (remove) {
8864 // Mark as remove if necessary
8865 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8866 }
8867 } else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8868 // Found open slot
8869 if (!agent_already_present) {
8870 uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8871 if (remove) {
8872 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8873 } else {
8874 returned_result->netagent_use_flags[netagent_cursor] = 0;
8875 }
8876 }
8877 break;
8878 }
8879 }
8880 }
8881
8882 // Update the local netagent_ids array for future evaluations
8883 if (remove) {
8884 // Check if the agent ID is in the array, and remove it
8885 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8886 if (netagent_id == netagent_ids[netagent_cursor]) {
8887 netagent_ids[netagent_cursor] = 0;
8888 }
8889 }
8890 } else {
8891 // Check if the agent ID is not yet in the array, and add it
8892 bool found = false;
8893 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8894 if (netagent_id == netagent_ids[netagent_cursor]) {
8895 found = true;
8896 break;
8897 }
8898 }
8899 if (!found) {
8900 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8901 if (netagent_ids[netagent_cursor] == 0) {
8902 // Empty slot, add the agent
8903 netagent_ids[netagent_cursor] = netagent_id;
8904 break;
8905 }
8906 }
8907 }
8908 }
8909 }
8910
8911 route_rule_index++;
8912 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8913 route_rule_index = 0;
8914 second_pass = true;
8915 }
8916 }
8917
8918 if (rt != NULL && rt->rt_ifp != NULL) {
8919 const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8920 const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8921 const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8922 IFNET_IS_EXPENSIVE(rt->rt_ifp));
8923 const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8924 IFNET_IS_CONSTRAINED(rt->rt_ifp));
8925 const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
8926 IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
8927 !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT)));
8928
8929 const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
8930 if (!is_listener && !is_browser) {
8931 if (reason != NULL) {
8932 if (expensive_prohibited) {
8933 *reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8934 } else if (constrained_prohibited) {
8935 *reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8936 } else if (ultra_constrained_not_allowed) {
8937 *reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8938 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_ULTRA_CONSTRAINED);
8939 }
8940 }
8941 if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
8942 // If a property of the interface was not allowed, treat it as a drop
8943 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8944 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8945 }
8946 }
8947 }
8948
8949 if (rt != NULL) {
8950 if (returned_route != NULL) {
8951 *returned_route = rt;
8952 } else {
8953 rtfree(rt);
8954 }
8955 rt = NULL;
8956 }
8957
8958 done:
8959 // Unlock
8960 lck_rw_done(&necp_kernel_policy_lock);
8961
8962 if (release_eproc && effective_proc != PROC_NULL) {
8963 proc_rele(effective_proc);
8964 }
8965 #if defined(XNU_TARGET_OS_OSX)
8966 if (responsible_proc != PROC_NULL) {
8967 proc_rele(responsible_proc);
8968 }
8969 #endif
8970
8971 if (cred != NULL) {
8972 kauth_cred_unref(&cred);
8973 }
8974
8975 return error;
8976 }
8977
8978 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)8979 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
8980 {
8981 struct rtentry *rt = NULL;
8982 bool is_local = FALSE;
8983
8984 if (remote_addr == NULL) {
8985 return NULL;
8986 }
8987
8988 if (remote_addr->sa.sa_len == 0 ||
8989 (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8990 (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8991 return FALSE;
8992 }
8993
8994 // Lookup route regardless of the scoped interface to check if
8995 // remote address is in a local network.
8996 rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
8997
8998 if (rt == NULL) {
8999 goto done;
9000 }
9001 if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
9002 goto free_rt;
9003 }
9004 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
9005
9006 free_rt:
9007 rtfree(rt);
9008
9009 done:
9010 return is_local;
9011 }
9012
9013 static bool
necp_socket_check_policy(struct necp_kernel_socket_policy * kernel_policy,necp_app_id app_id,necp_app_id real_app_id,uint8_t is_entitled,u_int32_t account_id,struct substring domain,u_int8_t domain_dot_count,const char * url __null_terminated,pid_t pid,int32_t pid_version,uid_t uid,uid_t real_uid,u_int32_t bound_interface_index,u_int32_t traffic_class,u_int16_t protocol,union necp_sockaddr_union * local,union necp_sockaddr_union * remote,struct necp_client_parameter_netagent_type * __counted_by (num_required_agent_types)required_agent_types,u_int32_t num_required_agent_types,bool has_client,uint32_t client_flags,int is_platform_binary,bool has_signed_result,proc_t proc,u_int16_t pf_tag,u_int16_t scheme_port,struct rtentry * rt,bool is_loopback,int debug,bool real_is_platform_binary,u_int32_t bound_interface_flags,u_int32_t bound_interface_eflags,u_int32_t bound_interface_xflags,struct necp_socket_info * info,bool is_delegated,struct socket * socket)9014 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
9015 necp_app_id app_id,
9016 necp_app_id real_app_id,
9017 uint8_t is_entitled,
9018 u_int32_t account_id,
9019 struct substring domain,
9020 u_int8_t domain_dot_count,
9021 const char *url __null_terminated,
9022 pid_t pid,
9023 int32_t pid_version,
9024 uid_t uid,
9025 uid_t real_uid,
9026 u_int32_t bound_interface_index,
9027 u_int32_t traffic_class,
9028 u_int16_t protocol,
9029 union necp_sockaddr_union *local,
9030 union necp_sockaddr_union *remote,
9031 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9032 u_int32_t num_required_agent_types,
9033 bool has_client,
9034 uint32_t client_flags,
9035 int is_platform_binary,
9036 bool has_signed_result,
9037 proc_t proc,
9038 u_int16_t pf_tag,
9039 u_int16_t scheme_port,
9040 struct rtentry *rt,
9041 bool is_loopback,
9042 int debug,
9043 bool real_is_platform_binary,
9044 u_int32_t bound_interface_flags,
9045 u_int32_t bound_interface_eflags,
9046 u_int32_t bound_interface_xflags,
9047 struct necp_socket_info *info,
9048 bool is_delegated,
9049 struct socket *socket)
9050 {
9051 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9052 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9053 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9054 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9055 "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
9056 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9057 if (bound_interface_index == cond_bound_interface_index) {
9058 // No match, matches forbidden interface
9059 return FALSE;
9060 }
9061 } else {
9062 if (bound_interface_index != cond_bound_interface_index) {
9063 // No match, does not match required interface
9064 return FALSE;
9065 }
9066 }
9067 }
9068 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9069 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9070 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9071 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9072 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9073 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9074 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9075 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9076 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9077 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9078 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9079 // No match, matches some forbidden interface flags
9080 return FALSE;
9081 }
9082 } else {
9083 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9084 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9085 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9086 // No match, does not match some required interface xflags
9087 return FALSE;
9088 }
9089 }
9090 }
9091 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9092 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9093 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
9094 if (bound_interface_index != 0) {
9095 // No match, requires a non-bound packet
9096 return FALSE;
9097 }
9098 }
9099 }
9100
9101 if (kernel_policy->condition_mask == 0) {
9102 return TRUE;
9103 }
9104
9105 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9106 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
9107 "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
9108 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
9109 if (app_id == kernel_policy->cond_app_id) {
9110 // No match, matches forbidden application
9111 return FALSE;
9112 }
9113 } else {
9114 if (app_id != kernel_policy->cond_app_id) {
9115 // No match, does not match required application
9116 return FALSE;
9117 }
9118 }
9119
9120 // Check signing identifier only after APP ID matched
9121 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
9122 kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9123 u_int8_t matched = necp_boolean_state_false;
9124 const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
9125 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
9126 "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
9127 kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
9128 signing_id ? signing_id : "<n/a>");
9129 if (signing_id != NULL) {
9130 if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
9131 matched = necp_boolean_state_true;
9132 }
9133 }
9134
9135 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9136 if (matched == necp_boolean_state_true) {
9137 return FALSE;
9138 }
9139 } else {
9140 if (matched != necp_boolean_state_true) {
9141 return FALSE;
9142 }
9143 }
9144 }
9145 }
9146
9147 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9148 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
9149 "NECP_KERNEL_CONDITION_REAL_APP_ID",
9150 kernel_policy->cond_real_app_id, real_app_id);
9151 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9152 if (real_app_id == kernel_policy->cond_real_app_id) {
9153 // No match, matches forbidden application
9154 return FALSE;
9155 }
9156 } else {
9157 if (real_app_id != kernel_policy->cond_real_app_id) {
9158 // No match, does not match required application
9159 return FALSE;
9160 }
9161 }
9162 }
9163
9164 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9165 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
9166 if (!has_client) {
9167 return FALSE;
9168 }
9169 }
9170
9171 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9172 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
9173 if (!is_entitled) {
9174 // Process is missing entitlement
9175 return FALSE;
9176 }
9177 }
9178
9179 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9180 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY, "NECP_KERNEL_CONDITION_PLATFORM_BINARY", 0, is_platform_binary);
9181 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9182 if (is_platform_binary) {
9183 // Process is platform binary
9184 return FALSE;
9185 }
9186 } else {
9187 if (!is_platform_binary) {
9188 // Process is not platform binary
9189 return FALSE;
9190 }
9191 }
9192 }
9193
9194 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9195 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
9196 if (has_signed_result == 0) {
9197 // Client did not have a system-signed result
9198 return FALSE;
9199 }
9200 }
9201
9202 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
9203 if (proc != NULL) {
9204 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
9205 kernel_policy->cond_sdk_version.platform,
9206 kernel_policy->cond_sdk_version.min_version,
9207 kernel_policy->cond_sdk_version.version,
9208 proc_platform(proc),
9209 proc_min_sdk(proc),
9210 proc_sdk(proc));
9211 if (kernel_policy->cond_sdk_version.platform != 0) {
9212 if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
9213 // Process does not match platform
9214 return FALSE;
9215 }
9216 }
9217
9218 if (kernel_policy->cond_sdk_version.min_version != 0) {
9219 if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
9220 // Process min version is older than required min version
9221 return FALSE;
9222 }
9223 }
9224
9225 if (kernel_policy->cond_sdk_version.version != 0) {
9226 if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
9227 // Process SDK version is older than required version
9228 return FALSE;
9229 }
9230 }
9231 }
9232 }
9233
9234 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
9235 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
9236 if (kernel_policy->cond_custom_entitlement != NULL) {
9237 if (proc == NULL) {
9238 // No process found, cannot check entitlement
9239 return FALSE;
9240 }
9241 task_t __single task = proc_task(proc);
9242 if (task == NULL ||
9243 !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
9244 // Process is missing custom entitlement
9245 return FALSE;
9246 }
9247 }
9248 }
9249
9250 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9251 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
9252 "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
9253 // Exact match requires the number of dots to match (no suffix matching allowed)
9254 bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
9255 necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
9256 if (domain_matches && socket != NULL) {
9257 socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9258 }
9259 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9260 if (domain_matches) {
9261 // No match, matches forbidden domain
9262 return FALSE;
9263 }
9264 } else {
9265 if (!domain_matches) {
9266 // No match, does not match required domain
9267 return FALSE;
9268 }
9269 }
9270 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9271 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
9272 "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
9273 bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
9274 if (domain_matches && socket != NULL) {
9275 socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9276 }
9277 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9278 if (domain_matches) {
9279 // No match, matches forbidden domain
9280 return FALSE;
9281 }
9282 } else {
9283 if (!domain_matches) {
9284 // No match, does not match required domain
9285 return FALSE;
9286 }
9287 }
9288 }
9289
9290 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9291 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9292 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (ID)", kernel_policy->cond_domain_filter, 0);
9293 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9294 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (domain)", "<n/a>", domain.string);
9295 bool domain_matches = false;
9296 if (NECP_IS_DOMAIN_FILTER_ID(kernel_policy->cond_domain_filter)) {
9297 struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
9298 if (filter != NULL && filter->filter != NULL) {
9299 domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
9300 }
9301 } else {
9302 domain_matches = necp_match_domain_with_trie(&necp_global_domain_trie_list, kernel_policy->cond_domain_filter, domain.string, domain.length);
9303 if (debug) {
9304 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);
9305 }
9306 }
9307 if (domain_matches && socket != NULL) {
9308 socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9309 }
9310 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9311 if (domain_matches) {
9312 // No match, matches forbidden domain
9313 return FALSE;
9314 }
9315 } else {
9316 if (!domain_matches) {
9317 // No match, does not match required domain
9318 return FALSE;
9319 }
9320 }
9321 }
9322
9323 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
9324 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
9325 "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
9326 bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
9327 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
9328 if (url_matches) {
9329 // No match, matches forbidden url
9330 return FALSE;
9331 }
9332 } else {
9333 if (!url_matches) {
9334 // No match, does not match required url
9335 return FALSE;
9336 }
9337 }
9338 }
9339
9340 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9341 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
9342 "NECP_KERNEL_CONDITION_ACCOUNT_ID",
9343 kernel_policy->cond_account_id, account_id);
9344 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9345 if (account_id == kernel_policy->cond_account_id) {
9346 // No match, matches forbidden account
9347 return FALSE;
9348 }
9349 } else {
9350 if (account_id != kernel_policy->cond_account_id) {
9351 // No match, does not match required account
9352 return FALSE;
9353 }
9354 }
9355 }
9356
9357 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
9358 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
9359 "NECP_KERNEL_CONDITION_PID",
9360 kernel_policy->cond_pid, pid);
9361 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
9362 if (pid == kernel_policy->cond_pid) {
9363 // No match, matches forbidden pid
9364 return FALSE;
9365 }
9366 if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
9367 return FALSE;
9368 }
9369 } else {
9370 if (pid != kernel_policy->cond_pid) {
9371 // No match, does not match required pid
9372 return FALSE;
9373 }
9374 if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
9375 return FALSE;
9376 }
9377 }
9378 }
9379
9380 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9381 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9382 "NECP_KERNEL_CONDITION_UID",
9383 kernel_policy->cond_uid, uid);
9384 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9385 if (uid == kernel_policy->cond_uid) {
9386 // No match, matches forbidden uid
9387 return FALSE;
9388 }
9389 } else {
9390 if (uid != kernel_policy->cond_uid) {
9391 // No match, does not match required uid
9392 return FALSE;
9393 }
9394 }
9395 }
9396
9397 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9398 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9399 "NECP_KERNEL_CONDITION_REAL_UID",
9400 kernel_policy->cond_real_uid, real_uid);
9401 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9402 if (real_uid == kernel_policy->cond_real_uid) {
9403 // No match, matches forbidden uid
9404 return FALSE;
9405 }
9406 } else {
9407 if (real_uid != kernel_policy->cond_real_uid) {
9408 // No match, does not match required uid
9409 return FALSE;
9410 }
9411 }
9412 }
9413
9414 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9415 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9416 kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9417 traffic_class, 0, 0);
9418 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9419 if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9420 traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9421 // No match, matches forbidden traffic class
9422 return FALSE;
9423 }
9424 } else {
9425 if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9426 traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9427 // No match, does not match required traffic class
9428 return FALSE;
9429 }
9430 }
9431 }
9432
9433 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9434 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9435 "NECP_KERNEL_CONDITION_PROTOCOL",
9436 kernel_policy->cond_protocol, protocol);
9437 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9438 if (protocol == kernel_policy->cond_protocol) {
9439 // No match, matches forbidden protocol
9440 return FALSE;
9441 }
9442 } else {
9443 if (protocol != kernel_policy->cond_protocol) {
9444 // No match, does not match required protocol
9445 return FALSE;
9446 }
9447 }
9448 }
9449
9450 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9451 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9452 kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9453 "n/a", "n/a", "n/a");
9454 bool matches_agent_type = FALSE;
9455 for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9456 struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9457 if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9458 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) &&
9459 (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9460 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)) {
9461 // Found a required agent that matches
9462 matches_agent_type = TRUE;
9463 break;
9464 }
9465 }
9466 if (!matches_agent_type) {
9467 return FALSE;
9468 }
9469 }
9470
9471 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9472 bool is_local = FALSE;
9473 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9474
9475 if (rt != NULL) {
9476 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9477 } else {
9478 is_local = necp_is_route_local(remote, include_local_addresses);
9479 }
9480 if (info != NULL) {
9481 info->is_local = is_local;
9482 }
9483
9484 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);
9485 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9486 if (is_local) {
9487 // Match local-networks, fail
9488 return FALSE;
9489 }
9490 } else {
9491 if (!is_local) {
9492 // Either no route to validate or no match for local networks
9493 return FALSE;
9494 }
9495 }
9496 }
9497
9498 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9499 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9500 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9501 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9502 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9503 if (inRange) {
9504 return FALSE;
9505 }
9506 } else {
9507 if (!inRange) {
9508 return FALSE;
9509 }
9510 }
9511 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9512 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9513 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);
9514 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9515 if (inSubnet) {
9516 return FALSE;
9517 }
9518 } else {
9519 if (!inSubnet) {
9520 return FALSE;
9521 }
9522 }
9523 }
9524 }
9525
9526 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9527 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9528 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9529 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9530 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9531 if (inRange) {
9532 return FALSE;
9533 }
9534 } else {
9535 if (!inRange) {
9536 return FALSE;
9537 }
9538 }
9539 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9540 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9541 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);
9542 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9543 if (inSubnet) {
9544 return FALSE;
9545 }
9546 } else {
9547 if (!inSubnet) {
9548 return FALSE;
9549 }
9550 }
9551 }
9552 }
9553
9554 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9555 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9556 "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9557 kernel_policy->cond_client_flags, client_flags);
9558 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9559 if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9560 // Flags do match, and condition is negative, fail.
9561 return FALSE;
9562 }
9563 } else {
9564 if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9565 // Flags do not match, fail.
9566 return FALSE;
9567 }
9568 }
9569 }
9570
9571 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9572 bool isEmpty = necp_addr_is_empty(SA(local));
9573 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9574 "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9575 0, isEmpty);
9576 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9577 if (isEmpty) {
9578 return FALSE;
9579 }
9580 } else {
9581 if (!isEmpty) {
9582 return FALSE;
9583 }
9584 }
9585 }
9586
9587 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9588 bool isEmpty = necp_addr_is_empty(SA(remote));
9589 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9590 "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9591 0, isEmpty);
9592 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9593 if (isEmpty) {
9594 return FALSE;
9595 }
9596 } else {
9597 if (!isEmpty) {
9598 return FALSE;
9599 }
9600 }
9601 }
9602
9603 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9604 u_int16_t remote_port = 0;
9605 if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9606 remote_port = SIN(remote)->sin_port;
9607 }
9608 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9609 "NECP_KERNEL_CONDITION_SCHEME_PORT",
9610 scheme_port, remote_port);
9611 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9612 if (kernel_policy->cond_scheme_port == scheme_port ||
9613 kernel_policy->cond_scheme_port == remote_port) {
9614 return FALSE;
9615 }
9616 } else {
9617 if (kernel_policy->cond_scheme_port != scheme_port &&
9618 kernel_policy->cond_scheme_port != remote_port) {
9619 return FALSE;
9620 }
9621 }
9622 }
9623
9624 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9625 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9626 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9627 kernel_policy->cond_packet_filter_tags,
9628 pf_tag);
9629 bool tags_matched = false;
9630 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9631 if (pf_tag == PF_TAG_ID_STACK_DROP) {
9632 tags_matched = true;
9633 }
9634 }
9635
9636 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9637 if (tags_matched) {
9638 return FALSE;
9639 }
9640 } else {
9641 if (!tags_matched) {
9642 return FALSE;
9643 }
9644 }
9645 }
9646
9647 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9648 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9649 "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9650 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9651 if (is_loopback) {
9652 return FALSE;
9653 }
9654 } else {
9655 if (!is_loopback) {
9656 return FALSE;
9657 }
9658 }
9659 }
9660
9661 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9662 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9663 "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9664 if (is_delegated) {
9665 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9666 if (real_is_platform_binary) {
9667 return FALSE;
9668 }
9669 } else {
9670 if (!real_is_platform_binary) {
9671 return FALSE;
9672 }
9673 }
9674 } else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9675 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9676 // If the connection is not delegated, and the policy did not specify a particular effective process UUID
9677 // or PID, check the process directly
9678 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9679 if (is_platform_binary) {
9680 return FALSE;
9681 }
9682 } else {
9683 if (!is_platform_binary) {
9684 return FALSE;
9685 }
9686 }
9687 }
9688 }
9689
9690 return TRUE;
9691 }
9692
9693 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9694 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9695 {
9696 return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9697 }
9698
9699 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)9700 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)
9701 {
9702 struct socket *so = NULL;
9703 proc_t sock_proc = NULL;
9704 proc_t curr_proc = current_proc();
9705
9706 memset(info, 0, sizeof(struct necp_socket_info));
9707
9708 so = inp->inp_socket;
9709
9710 info->drop_order = drop_order;
9711 info->is_loopback = is_loopback;
9712 info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9713
9714 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9715 necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9716 info->uid = kauth_cred_getuid(so->so_cred);
9717 info->real_uid = info->uid;
9718 }
9719
9720 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9721 info->traffic_class = so->so_traffic_class;
9722 }
9723
9724 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9725 info->has_client = !uuid_is_null(inp->necp_client_uuid);
9726 }
9727
9728 if (inp->inp_ip_p) {
9729 info->protocol = inp->inp_ip_p;
9730 } else {
9731 info->protocol = SOCK_PROTO(so);
9732 }
9733
9734 if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9735 u_int32_t responsible_application_id = 0;
9736
9737 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9738 if (existing_mapping) {
9739 info->application_id = existing_mapping->id;
9740 }
9741
9742 #if defined(XNU_TARGET_OS_OSX)
9743 if (so->so_rpid > 0) {
9744 existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9745 if (existing_mapping != NULL) {
9746 responsible_application_id = existing_mapping->id;
9747 }
9748 }
9749 #endif
9750
9751 if (responsible_application_id > 0) {
9752 info->real_application_id = info->application_id;
9753 info->application_id = responsible_application_id;
9754 info->used_responsible_pid = true;
9755 } else if (!(so->so_flags & SOF_DELEGATED)) {
9756 info->real_application_id = info->application_id;
9757 } else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9758 struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9759 if (real_existing_mapping) {
9760 info->real_application_id = real_existing_mapping->id;
9761 }
9762 }
9763 }
9764
9765 pid_t socket_pid =
9766 #if defined(XNU_TARGET_OS_OSX)
9767 info->used_responsible_pid ? so->so_rpid :
9768 #endif
9769 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9770 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9771 sock_proc = proc_find(socket_pid);
9772 if (socket_proc) {
9773 *socket_proc = sock_proc;
9774 }
9775 }
9776
9777 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9778 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9779 info->is_entitled = necp_task_has_match_entitlement(task);
9780 if (!info->is_entitled) {
9781 // Task does not have entitlement, check the parent task
9782 necp_get_parent_is_entitled(task, info);
9783 }
9784 }
9785
9786 info->pid = socket_pid;
9787 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9788 info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9789 }
9790
9791 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9792 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9793 if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9794 info->is_platform_binary = true;
9795 } else if (so->so_rpid != 0) {
9796 proc_t responsible_proc = proc_find(so->so_rpid);
9797 if (responsible_proc != NULL) {
9798 if (necp_is_platform_binary(responsible_proc)) {
9799 info->is_platform_binary = true;
9800 info->used_responsible_pid = true;
9801 }
9802 proc_rele(responsible_proc);
9803 }
9804 }
9805 }
9806
9807 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9808 proc_t real_proc = curr_proc;
9809 bool release_real_proc = false;
9810 if (so->last_pid != proc_pid(real_proc)) {
9811 if (so->last_pid == socket_pid && sock_proc != NULL) {
9812 real_proc = sock_proc;
9813 } else {
9814 proc_t last_proc = proc_find(so->last_pid);
9815 if (last_proc != NULL) {
9816 real_proc = last_proc;
9817 release_real_proc = true;
9818 }
9819 }
9820 }
9821 if (real_proc != NULL) {
9822 if (real_proc == kernproc) {
9823 info->real_is_platform_binary = true;
9824 } else {
9825 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9826 }
9827 if (release_real_proc) {
9828 proc_rele(real_proc);
9829 }
9830 }
9831 }
9832
9833 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9834 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9835 if (existing_mapping) {
9836 info->account_id = existing_mapping->id;
9837 }
9838 }
9839
9840 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9841 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9842 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9843 info->domain = inp->inp_necp_attributes.inp_domain;
9844 }
9845
9846 if (override_bound_interface) {
9847 info->bound_interface_index = override_bound_interface;
9848 } else {
9849 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9850 info->bound_interface_index = inp->inp_boundifp->if_index;
9851 }
9852 }
9853
9854 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9855 info->bound_interface_index != IFSCOPE_NONE) {
9856 ifnet_head_lock_shared();
9857 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9858 if (interface != NULL) {
9859 info->bound_interface_flags = interface->if_flags;
9860 info->bound_interface_eflags = interface->if_eflags;
9861 info->bound_interface_xflags = interface->if_xflags;
9862 }
9863 ifnet_head_done();
9864 }
9865
9866 bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9867 uuid_is_null(inp->necp_client_uuid) &&
9868 necp_socket_has_resolver_signature(inp));
9869 if ((necp_data_tracing_level && necp_data_tracing_port) ||
9870 necp_restrict_multicast ||
9871 needs_address_for_signature ||
9872 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) ||
9873 NEED_DGRAM_FLOW_TRACKING(so)) {
9874 if (override_local_addr != NULL) {
9875 if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9876 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9877 if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9878 struct sockaddr_in sin;
9879 in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9880 memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9881 memcpy(&info->local_addr, &sin, sin.sin_len);
9882 }
9883 } else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9884 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9885 }
9886 } else {
9887 if (inp->inp_vflag & INP_IPV6) {
9888 SIN6(&info->local_addr)->sin6_family = AF_INET6;
9889 SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9890 SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9891 memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9892 } else if (inp->inp_vflag & INP_IPV4) {
9893 SIN(&info->local_addr)->sin_family = AF_INET;
9894 SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9895 SIN(&info->local_addr)->sin_port = inp->inp_lport;
9896 memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9897 }
9898 }
9899
9900 if (override_remote_addr != NULL) {
9901 if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9902 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9903 if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9904 struct sockaddr_in sin;
9905 in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9906 memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9907 memcpy(&info->remote_addr, &sin, sin.sin_len);
9908 }
9909 } else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9910 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9911 }
9912 } else {
9913 if (inp->inp_vflag & INP_IPV6) {
9914 SIN6(&info->remote_addr)->sin6_family = AF_INET6;
9915 SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9916 SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
9917 memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
9918 } else if (inp->inp_vflag & INP_IPV4) {
9919 SIN(&info->remote_addr)->sin_family = AF_INET;
9920 SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9921 SIN(&info->remote_addr)->sin_port = inp->inp_fport;
9922 memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
9923 }
9924 }
9925 // Clear the embedded scope id from v6 addresses
9926 if (info->local_addr.sa.sa_family == AF_INET6) {
9927 struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
9928 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9929 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9930 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9931 sin6->sin6_addr.s6_addr16[1] = 0;
9932 }
9933 }
9934 }
9935 if (info->remote_addr.sa.sa_family == AF_INET6) {
9936 struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
9937 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9938 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9939 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9940 sin6->sin6_addr.s6_addr16[1] = 0;
9941 }
9942 }
9943 }
9944 }
9945
9946 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9947 // For checking sockets, only validate that there is an NECP client present. It will have
9948 // already checked for the signature.
9949 if (!uuid_is_null(inp->necp_client_uuid)) {
9950 info->has_system_signed_result = true;
9951 } else {
9952 info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
9953 }
9954 }
9955
9956 if (NEED_DGRAM_FLOW_TRACKING(so)) {
9957 info->soflow_entry = soflow_get_flow(so, NULL, &(info->remote_addr.sa), NULL, 0, override_direction, input_ifindex);
9958 } else {
9959 info->soflow_entry = NULL;
9960 }
9961
9962 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9963 info->client_flags = 0;
9964 if (INP_NO_CONSTRAINED(inp)) {
9965 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
9966 }
9967 if (INP_NO_EXPENSIVE(inp)) {
9968 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
9969 }
9970 if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
9971 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
9972 }
9973 if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
9974 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
9975 }
9976 if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
9977 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
9978 }
9979 if (NEED_DGRAM_FLOW_TRACKING(so)) {
9980 // If the socket has a flow entry for this 4-tuple then check if the flow is outgoing
9981 // and set the inbound flag accordingly. Otherwise use the direction to set the inbound flag.
9982 if (info->soflow_entry != NULL) {
9983 if (!info->soflow_entry->soflow_outgoing) {
9984 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9985 }
9986 } else if (override_direction == SOFLOW_DIRECTION_INBOUND) {
9987 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9988 }
9989 } else {
9990 // If the socket is explicitly marked as inbound then set the inbound flag.
9991 if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
9992 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9993 }
9994 }
9995 if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
9996 inp->inp_flags2 & INP2_EXTERNAL_PORT) {
9997 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
9998 }
9999 if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
10000 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
10001 }
10002 if (inp->inp_socket->so_options & SO_REUSEPORT) {
10003 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
10004 }
10005 }
10006 }
10007
10008 #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)
10009
10010 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)10011 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
10012 struct necp_socket_info *info,
10013 necp_kernel_policy_filter *return_filter,
10014 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
10015 size_t *return_route_rule_id_array_count,
10016 size_t route_rule_id_array_count,
10017 necp_kernel_policy_result *return_service_action,
10018 necp_kernel_policy_service *return_service,
10019 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
10020 size_t netagent_array_count,
10021 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
10022 size_t netagent_use_flags_array_count,
10023 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
10024 u_int32_t num_required_agent_types,
10025 proc_t proc,
10026 u_int16_t pf_tag,
10027 necp_kernel_policy_id *skip_policy_id,
10028 struct rtentry *rt,
10029 necp_kernel_policy_result *return_drop_dest_policy_result,
10030 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
10031 u_int32_t *return_flow_divert_aggregate_unit,
10032 struct socket *so,
10033 int debug)
10034 {
10035 struct necp_kernel_socket_policy *matched_policy = NULL;
10036 u_int32_t skip_order = 0;
10037 u_int32_t skip_session_order = 0;
10038 bool skipped_ip_result = false;
10039 size_t route_rule_id_count = 0;
10040 int i;
10041 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10042 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
10043 memset(&netagent_ids, 0, sizeof(netagent_ids));
10044 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
10045 size_t netagent_cursor = 0;
10046 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10047 size_t netagent_array_count_adjusted = netagent_array_count;
10048 if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
10049 netagent_array_count_adjusted = netagent_use_flags_array_count;
10050 }
10051
10052 if (return_drop_all_bypass != NULL) {
10053 *return_drop_all_bypass = drop_all_bypass;
10054 }
10055
10056 if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
10057 netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
10058 }
10059
10060 // Pre-process domain for quick matching
10061 struct substring domain_substring = {};
10062 u_int8_t domain_dot_count = 0;
10063 if (info->domain != NULL) {
10064 domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
10065 domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
10066 }
10067
10068 if (return_filter != NULL) {
10069 *return_filter = 0;
10070 }
10071
10072 if (return_route_rule_id_array_count != NULL) {
10073 *return_route_rule_id_array_count = 0;
10074 }
10075
10076 if (return_service_action != NULL) {
10077 *return_service_action = 0;
10078 }
10079
10080 if (return_service != NULL) {
10081 return_service->identifier = 0;
10082 return_service->data = 0;
10083 }
10084
10085 // Do not subject layer-2 filter to NECP policies, return a PASS policy
10086 if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
10087 return &pass_policy;
10088 }
10089
10090 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10091
10092 if (policy_search_array != NULL) {
10093 for (i = 0; policy_search_array[i] != NULL; i++) {
10094 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
10095
10096 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10097 // We've hit a drop all rule
10098 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10099 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
10100 if (return_drop_all_bypass != NULL) {
10101 *return_drop_all_bypass = drop_all_bypass;
10102 }
10103 }
10104 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10105 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
10106 break;
10107 }
10108 }
10109 if (necp_drop_dest_policy.entry_count != 0 &&
10110 necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
10111 // We've hit a drop by destination address rule
10112 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10113 break;
10114 }
10115 if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
10116 // We've hit a drop order for this socket
10117 break;
10118 }
10119 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10120 // Done skipping
10121 skip_order = 0;
10122 skip_session_order = 0;
10123 // If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
10124 if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
10125 *skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10126 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
10127 }
10128 }
10129 if (skip_order) {
10130 if (policy_search_array[i]->order < skip_order) {
10131 // Skip this policy
10132 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10133 // didn't, clear out the return value for skip ID when we are done with each session.'
10134 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10135 skipped_ip_result = true;
10136 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10137 }
10138 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
10139 continue;
10140 } else {
10141 // Done skipping
10142 skip_order = 0;
10143 skip_session_order = 0;
10144 }
10145 } else if (skip_session_order) {
10146 // Skip this policy
10147 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10148 // didn't, clear out the return value for skip ID when we are done with each session.'
10149 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10150 skipped_ip_result = true;
10151 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10152 }
10153 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
10154 continue;
10155 }
10156
10157 if (necp_socket_check_policy(policy_search_array[i],
10158 info->application_id,
10159 info->real_application_id,
10160 info->is_entitled,
10161 info->account_id,
10162 domain_substring,
10163 domain_dot_count,
10164 info->url,
10165 info->pid,
10166 info->pid_version,
10167 info->uid,
10168 info->real_uid,
10169 info->bound_interface_index,
10170 info->traffic_class,
10171 info->protocol,
10172 &info->local_addr,
10173 &info->remote_addr,
10174 required_agent_types,
10175 num_required_agent_types,
10176 info->has_client,
10177 info->client_flags,
10178 info->is_platform_binary,
10179 info->has_system_signed_result,
10180 proc,
10181 pf_tag,
10182 info->scheme_port,
10183 rt,
10184 info->is_loopback,
10185 debug,
10186 info->real_is_platform_binary,
10187 info->bound_interface_flags,
10188 info->bound_interface_eflags,
10189 info->bound_interface_xflags,
10190 info,
10191 info->is_delegated,
10192 so)) {
10193 if (!debug && necp_data_tracing_session_order) {
10194 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10195 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10196 NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
10197 }
10198 }
10199
10200 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
10201 if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
10202 necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
10203 if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
10204 *return_filter = control_unit;
10205 } else {
10206 // Preserve pre-existing connections only if all filters preserve.
10207 bool preserve_bit_off = false;
10208 if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
10209 (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
10210 preserve_bit_off = true;
10211 }
10212 *return_filter |= control_unit;
10213 if (preserve_bit_off == true) {
10214 *return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
10215 }
10216 }
10217 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10218 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);
10219 }
10220 }
10221 continue;
10222 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10223 if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
10224 return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10225 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10226 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);
10227 }
10228 }
10229 continue;
10230 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
10231 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10232 if (netagent_cursor < netagent_array_count_adjusted) {
10233 bool agent_already_present = false;
10234 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10235 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10236 // Already present. Mark the "SCOPED" flag if flags are necessary.
10237 agent_already_present = true;
10238 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
10239 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10240 netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
10241 }
10242 }
10243 }
10244
10245 if (!agent_already_present) {
10246 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10247 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10248 netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
10249 }
10250 netagent_cursor++;
10251 }
10252 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10253 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
10254 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10255 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
10256 policy_search_array[i]->result_parameter.netagent_id);
10257 }
10258 }
10259 continue;
10260 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
10261 bool agent_already_present = false;
10262 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10263 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10264 // Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10265 agent_already_present = true;
10266 netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10267 }
10268 }
10269 if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10270 // If not present, and flags are supported, add an entry with the "REMOVE" flag
10271 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10272 netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10273 netagent_cursor++;
10274 }
10275 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10276 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
10277 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10278 policy_search_array[i]->result_parameter.netagent_id);
10279 }
10280 continue;
10281 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
10282 u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
10283 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
10284 /* For transparent proxies, accumulate the control unit and continue to the next policy */
10285 if (return_flow_divert_aggregate_unit != NULL) {
10286 *return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
10287 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10288 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);
10289 }
10290 }
10291 continue;
10292 }
10293 }
10294
10295 // Matched policy is a skip. Do skip and continue.
10296 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10297 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
10298 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10299 skip_session_order = policy_search_array[i]->session_order + 1;
10300 if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
10301 *skip_policy_id = policy_search_array[i]->id;
10302 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10303 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);
10304 }
10305 }
10306 continue;
10307 }
10308
10309 // Matched an allow unentitled, which clears any drop order
10310 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
10311 info->drop_order = 0;
10312 continue;
10313 }
10314
10315 // Passed all tests, found a match
10316 matched_policy = policy_search_array[i];
10317 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
10318 break;
10319 }
10320 }
10321 }
10322
10323 if (return_netagent_array != NULL) {
10324 if (return_netagent_use_flags_array != NULL) {
10325 memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
10326 memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
10327 } else {
10328 for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
10329 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
10330 return_netagent_array[netagent_i] = netagent_ids[netagent_i];
10331 } else {
10332 return_netagent_array[netagent_i] = 0;
10333 }
10334 }
10335 }
10336 }
10337
10338 if (return_route_rule_id_array_count != NULL) {
10339 *return_route_rule_id_array_count = route_rule_id_count;
10340 }
10341 return matched_policy;
10342 }
10343
10344 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)10345 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
10346 {
10347 bool found_match = FALSE;
10348 ifaddr_t ifa;
10349 union necp_sockaddr_union address_storage;
10350 int family = AF_INET;
10351
10352 ifnet_head_lock_shared();
10353 ifnet_t interface = ifindex2ifnet[interface_index];
10354 ifnet_head_done();
10355
10356 if (inp == NULL || interface == NULL) {
10357 return FALSE;
10358 }
10359
10360 if (inp->inp_vflag & INP_IPV4) {
10361 family = AF_INET;
10362 } else if (inp->inp_vflag & INP_IPV6) {
10363 family = AF_INET6;
10364 } else {
10365 return FALSE;
10366 }
10367
10368 // Match socket address against interface addresses
10369 ifnet_lock_shared(interface);
10370 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
10371 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
10372 if (address_storage.sa.sa_family != family) {
10373 continue;
10374 }
10375
10376 if (family == AF_INET) {
10377 if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
10378 found_match = TRUE;
10379 break;
10380 }
10381 } else if (family == AF_INET6) {
10382 if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
10383 found_match = TRUE;
10384 break;
10385 }
10386 }
10387 }
10388 }
10389 ifnet_lock_done(interface);
10390
10391 return found_match;
10392 }
10393
10394 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10395 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10396 {
10397 if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10398 proc_t curr_proc = current_proc();
10399 proc_t sock_proc = NULL;
10400 struct socket *so = inp ? inp->inp_socket : NULL;
10401 pid_t socket_pid = (so == NULL) ? 0 :
10402 #if defined(XNU_TARGET_OS_OSX)
10403 so->so_rpid ? so->so_rpid :
10404 #endif
10405 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10406 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10407 sock_proc = proc_find(socket_pid);
10408 }
10409 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10410 if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10411 if (sock_proc) {
10412 proc_rele(sock_proc);
10413 }
10414 return NECP_BYPASS_TYPE_DROP;
10415 }
10416 if (sock_proc) {
10417 proc_rele(sock_proc);
10418 }
10419
10420 if (necp_pass_loopback > 0) {
10421 return NECP_BYPASS_TYPE_LOOPBACK;
10422 }
10423 } else if (necp_is_intcoproc(inp, NULL)) {
10424 return NECP_BYPASS_TYPE_INTCOPROC;
10425 }
10426
10427 return NECP_BYPASS_TYPE_NONE;
10428 }
10429
10430 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10431 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10432 {
10433 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10434 ifnet_t tunnel_interface = NULL;
10435
10436 ifnet_head_lock_shared();
10437 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10438 ifnet_head_done();
10439
10440 if (tunnel_interface != NULL) {
10441 tcp_set_tso(intotcpcb(inp), tunnel_interface);
10442 }
10443 }
10444
10445 static inline void
necp_unscope(struct inpcb * inp)10446 necp_unscope(struct inpcb *inp)
10447 {
10448 // If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10449 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10450 inp->inp_flags &= ~INP_BOUND_IF;
10451 inp->inp_boundifp = NULL;
10452 }
10453 }
10454
10455 static inline void
necp_clear_tunnel(struct inpcb * inp)10456 necp_clear_tunnel(struct inpcb *inp)
10457 {
10458 if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10459 inp->inp_flags &= ~INP_BOUND_IF;
10460 inp->inp_boundifp = NULL;
10461 }
10462 }
10463
10464 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10465 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10466 {
10467 // Verify netagents
10468 for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10469 struct necp_uuid_id_mapping *mapping = NULL;
10470 u_int32_t netagent_id = netagent_ids[netagent_cursor];
10471 if (netagent_id == 0) {
10472 continue;
10473 }
10474 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
10475 if (mapping != NULL) {
10476 u_int32_t agent_flags = 0;
10477 agent_flags = netagent_get_flags(mapping->uuid);
10478 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10479 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10480 continue;
10481 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10482 if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10483 int trigger_error = 0;
10484 trigger_error = netagent_kernel_trigger(mapping->uuid);
10485 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10486 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);
10487 }
10488 }
10489 return false;
10490 }
10491 }
10492 }
10493 }
10494 return true;
10495 }
10496
10497 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)10498 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10499 {
10500 struct socket *so = NULL;
10501 necp_kernel_policy_filter filter_control_unit = 0;
10502 struct necp_kernel_socket_policy *matched_policy = NULL;
10503 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10504 necp_kernel_policy_result service_action = 0;
10505 necp_kernel_policy_service service = { 0, 0 };
10506 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10507 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10508 proc_t __single socket_proc = NULL;
10509 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10510
10511 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10512 memset(&netagent_ids, 0, sizeof(netagent_ids));
10513
10514 struct necp_socket_info info = {};
10515
10516 u_int32_t flow_divert_aggregate_unit = 0;
10517
10518 if (inp == NULL) {
10519 return NECP_KERNEL_POLICY_ID_NONE;
10520 }
10521
10522 // Ignore invalid addresses
10523 if (override_local_addr != NULL &&
10524 !necp_address_is_valid(override_local_addr)) {
10525 override_local_addr = NULL;
10526 }
10527 if (override_remote_addr != NULL &&
10528 !necp_address_is_valid(override_remote_addr)) {
10529 override_remote_addr = NULL;
10530 }
10531
10532 so = inp->inp_socket;
10533
10534 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10535
10536 // Don't lock. Possible race condition, but we don't want the performance hit.
10537 if (necp_drop_management_order == 0 &&
10538 (necp_kernel_socket_policies_count == 0 ||
10539 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10540 if (necp_drop_all_order > 0 || drop_order > 0) {
10541 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10542 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10543 inp->inp_policyresult.policy_gencount = 0;
10544 inp->inp_policyresult.app_id = 0;
10545 inp->inp_policyresult.flowhash = 0;
10546 inp->inp_policyresult.results.filter_control_unit = 0;
10547 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10548 inp->inp_policyresult.results.route_rule_id = 0;
10549 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10550 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10551 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10552 } else {
10553 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10554 }
10555 }
10556 return NECP_KERNEL_POLICY_ID_NONE;
10557 }
10558
10559 // Check for loopback exception
10560 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10561 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10562 // Mark socket as a drop
10563 necp_unscope(inp);
10564 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10565 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10566 inp->inp_policyresult.policy_gencount = 0;
10567 inp->inp_policyresult.app_id = 0;
10568 inp->inp_policyresult.flowhash = 0;
10569 inp->inp_policyresult.results.filter_control_unit = 0;
10570 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10571 inp->inp_policyresult.results.route_rule_id = 0;
10572 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10573 return NECP_KERNEL_POLICY_ID_NONE;
10574 }
10575
10576 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10577 // Mark socket as a pass
10578 necp_unscope(inp);
10579 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10580 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10581 inp->inp_policyresult.policy_gencount = 0;
10582 inp->inp_policyresult.app_id = 0;
10583 inp->inp_policyresult.flowhash = 0;
10584 inp->inp_policyresult.results.filter_control_unit = 0;
10585 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10586 inp->inp_policyresult.results.route_rule_id = 0;
10587 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10588 return NECP_KERNEL_POLICY_ID_NONE;
10589 }
10590
10591 // Lock
10592 lck_rw_lock_shared(&necp_kernel_policy_lock);
10593 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);
10594
10595 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10596 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10597
10598 // Check info
10599 u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10600 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10601 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10602 inp->inp_policyresult.flowhash == flowhash) {
10603 // If already matched this socket on this generation of table, skip
10604
10605 if (info.soflow_entry != NULL) {
10606 soflow_free_flow(info.soflow_entry);
10607 }
10608
10609 // Unlock
10610 lck_rw_done(&necp_kernel_policy_lock);
10611
10612 if (socket_proc) {
10613 proc_rele(socket_proc);
10614 }
10615
10616 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10617 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10618 inp->inp_socket, info.bound_interface_index, info.protocol,
10619 inp->inp_policyresult.policy_id,
10620 inp->inp_policyresult.results.result,
10621 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10622 }
10623 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10624 return inp->inp_policyresult.policy_id;
10625 }
10626
10627 inp->inp_policyresult.app_id = info.application_id;
10628
10629 // Match socket to policy
10630 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10631 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10632 size_t route_rule_id_array_count = 0;
10633
10634 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10635 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)],
10636 &info,
10637 &filter_control_unit,
10638 route_rule_id_array,
10639 &route_rule_id_array_count,
10640 MAX_AGGREGATE_ROUTE_RULES,
10641 &service_action,
10642 &service,
10643 netagent_ids,
10644 NECP_MAX_NETAGENTS,
10645 NULL,
10646 0,
10647 NULL,
10648 0,
10649 effective_proc,
10650 0,
10651 &skip_policy_id,
10652 inp->inp_route.ro_rt,
10653 &drop_dest_policy_result,
10654 &drop_all_bypass,
10655 &flow_divert_aggregate_unit,
10656 so,
10657 debug);
10658
10659 // Check for loopback exception again after the policy match
10660 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10661 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10662 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10663 // Mark socket as a pass
10664 necp_unscope(inp);
10665 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10666 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10667 inp->inp_policyresult.policy_gencount = 0;
10668 inp->inp_policyresult.app_id = 0;
10669 inp->inp_policyresult.flowhash = 0;
10670 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10671 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10672 inp->inp_policyresult.results.route_rule_id = 0;
10673 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10674 if (info.soflow_entry != NULL) {
10675 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10676 info.soflow_entry->soflow_policies_gencount = 0;
10677 soflow_free_flow(info.soflow_entry);
10678 }
10679
10680 // Unlock
10681 lck_rw_done(&necp_kernel_policy_lock);
10682
10683 if (socket_proc) {
10684 proc_rele(socket_proc);
10685 }
10686
10687 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10688 return NECP_KERNEL_POLICY_ID_NONE;
10689 }
10690
10691 // Verify netagents
10692 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10693 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10694 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);
10695 }
10696
10697 // Mark socket as a drop if required agent is not active
10698 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10699 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10700 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10701 inp->inp_policyresult.flowhash = flowhash;
10702 inp->inp_policyresult.results.filter_control_unit = 0;
10703 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10704 inp->inp_policyresult.results.route_rule_id = 0;
10705 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10706 if (info.soflow_entry != NULL) {
10707 info.soflow_entry->soflow_filter_control_unit = 0;
10708 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10709 soflow_free_flow(info.soflow_entry);
10710 }
10711
10712 // Unlock
10713 lck_rw_done(&necp_kernel_policy_lock);
10714
10715 if (socket_proc) {
10716 proc_rele(socket_proc);
10717 }
10718
10719 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);
10720 return NECP_KERNEL_POLICY_ID_NONE;
10721 }
10722
10723 u_int32_t route_rule_id = 0;
10724 if (route_rule_id_array_count == 1) {
10725 route_rule_id = route_rule_id_array[0];
10726 } else if (route_rule_id_array_count > 1) {
10727 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10728 }
10729
10730 bool reset_tcp_tunnel_interface = false;
10731 bool send_local_network_denied_event = false;
10732 if (matched_policy) {
10733 // For PASS policy result, clear previous rescope / tunnel inteface
10734 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10735 (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10736 necp_unscope(inp);
10737 necp_clear_tunnel(inp);
10738 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10739 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10740 }
10741 }
10742 matched_policy_id = matched_policy->id;
10743 inp->inp_policyresult.policy_id = matched_policy->id;
10744 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10745 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10746 inp->inp_policyresult.flowhash = flowhash;
10747 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10748 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10749 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10750 inp->inp_policyresult.results.result = matched_policy->result;
10751 memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10752 if (info.soflow_entry != NULL) {
10753 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10754 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10755 }
10756
10757 if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10758 inp->inp_policyresult.app_id = info.real_application_id;
10759 }
10760
10761 if (necp_socket_is_connected(inp) &&
10762 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10763 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10764 NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10765 sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10766 } else if (necp_socket_is_connected(inp) &&
10767 matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10768 info.protocol == IPPROTO_TCP) {
10769 // Reset TCP socket interface based parameters if tunnel policy changes
10770 reset_tcp_tunnel_interface = true;
10771 }
10772
10773 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10774 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);
10775 }
10776
10777 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10778 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10779 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10780 // Trigger the event that we dropped due to a local network policy
10781 send_local_network_denied_event = true;
10782 }
10783 } else {
10784 bool drop_all = false;
10785 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10786 // Mark socket as a drop if set
10787 drop_all = true;
10788 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10789 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10790 }
10791 }
10792
10793 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10794 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);
10795 if (flow_divert_control_unit != 0) {
10796 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10797 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10798 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10799 inp->inp_policyresult.flowhash = flowhash;
10800 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10801 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10802 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10803 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10804 inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10805 if (info.soflow_entry != NULL) {
10806 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10807 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10808 }
10809 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);
10810 } else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10811 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10812 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10813 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10814 inp->inp_policyresult.flowhash = flowhash;
10815 inp->inp_policyresult.results.filter_control_unit = 0;
10816 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10817 inp->inp_policyresult.results.route_rule_id = 0;
10818 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10819 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);
10820 if (info.soflow_entry != NULL) {
10821 info.soflow_entry->soflow_filter_control_unit = 0;
10822 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10823 }
10824 } else {
10825 // Mark non-matching socket so we don't re-check it
10826 necp_unscope(inp);
10827 if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10828 necp_clear_tunnel(inp);
10829 }
10830 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10831 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);
10832 }
10833 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10834 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10835 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10836 inp->inp_policyresult.flowhash = flowhash;
10837 inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10838 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10839 inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10840 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10841 if (info.soflow_entry != NULL) {
10842 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10843 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10844 }
10845 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10846 }
10847 }
10848
10849 if (necp_check_missing_client_drop(effective_proc, &info) ||
10850 necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10851 // Mark as drop
10852 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10853 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10854 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10855 inp->inp_policyresult.flowhash = flowhash;
10856 inp->inp_policyresult.results.filter_control_unit = 0;
10857 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10858 inp->inp_policyresult.results.route_rule_id = 0;
10859 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10860 if (info.soflow_entry != NULL) {
10861 info.soflow_entry->soflow_filter_control_unit = 0;
10862 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10863 }
10864 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10865 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10866 }
10867 }
10868
10869 if (info.soflow_entry != NULL) {
10870 soflow_free_flow(info.soflow_entry);
10871 }
10872
10873 // Unlock
10874 lck_rw_done(&necp_kernel_policy_lock);
10875
10876 if (reset_tcp_tunnel_interface) {
10877 // Update MSS when not holding the policy lock to avoid recursive locking
10878 tcp_mtudisc(inp, 0);
10879
10880 // Update TSO flag based on the tunnel interface
10881 necp_socket_ip_tunnel_tso(inp);
10882 }
10883
10884 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10885 inp->inp_policyresult.network_denied_notifies++;
10886 #if defined(XNU_TARGET_OS_OSX)
10887 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10888 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10889 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10890 NETPOLICY_NETWORKTYPE_LOCAL);
10891 #else
10892 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10893 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10894 NETPOLICY_NETWORKTYPE_LOCAL);
10895 #endif
10896 }
10897
10898 if (socket_proc) {
10899 proc_rele(socket_proc);
10900 }
10901
10902 return matched_policy_id;
10903 }
10904
10905 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)10906 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)
10907 {
10908 u_int32_t bound_interface_flags = 0;
10909 u_int32_t bound_interface_eflags = 0;
10910 u_int32_t bound_interface_xflags = 0;
10911
10912 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
10913 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10914 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
10915 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
10916 "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
10917 cond_bound_interface_index, bound_interface_index);
10918 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10919 if (bound_interface_index == cond_bound_interface_index) {
10920 // No match, matches forbidden interface
10921 return FALSE;
10922 }
10923 } else {
10924 if (bound_interface_index != cond_bound_interface_index) {
10925 // No match, does not match required interface
10926 return FALSE;
10927 }
10928 }
10929 }
10930 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10931 if (bound_interface_index != IFSCOPE_NONE) {
10932 ifnet_head_lock_shared();
10933 ifnet_t interface = ifindex2ifnet[bound_interface_index];
10934 if (interface != NULL) {
10935 bound_interface_flags = interface->if_flags;
10936 bound_interface_eflags = interface->if_eflags;
10937 bound_interface_xflags = interface->if_xflags;
10938 }
10939 ifnet_head_done();
10940 }
10941
10942 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10943 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
10944 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10945 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
10946 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10947 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
10948 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10949 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10950 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10951 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10952 // No match, matches some forbidden interface flags
10953 return FALSE;
10954 }
10955 } else {
10956 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10957 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10958 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10959 // No match, does not match some required interface xflags
10960 return FALSE;
10961 }
10962 }
10963 }
10964 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
10965 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
10966 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
10967 if (bound_interface_index != 0) {
10968 // No match, requires a non-bound packet
10969 return FALSE;
10970 }
10971 }
10972 }
10973
10974 if (kernel_policy->condition_mask == 0) {
10975 return TRUE;
10976 }
10977
10978 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10979 necp_kernel_policy_id matched_policy_id =
10980 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10981 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
10982 "NECP_KERNEL_CONDITION_POLICY_ID",
10983 kernel_policy->cond_policy_id, 0, 0,
10984 matched_policy_id, socket_policy_id, socket_skip_policy_id);
10985 if (matched_policy_id != kernel_policy->cond_policy_id) {
10986 // No match, does not match required id
10987 return FALSE;
10988 }
10989 }
10990
10991 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10992 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
10993 "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10994 kernel_policy->cond_last_interface_index, last_interface_index);
10995 if (last_interface_index != kernel_policy->cond_last_interface_index) {
10996 return FALSE;
10997 }
10998 }
10999
11000 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11001 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
11002 "NECP_KERNEL_CONDITION_PROTOCOL",
11003 kernel_policy->cond_protocol, protocol);
11004 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11005 if (protocol == kernel_policy->cond_protocol) {
11006 // No match, matches forbidden protocol
11007 return FALSE;
11008 }
11009 } else {
11010 if (protocol != kernel_policy->cond_protocol) {
11011 // No match, does not match required protocol
11012 return FALSE;
11013 }
11014 }
11015 }
11016
11017 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11018 bool is_local = FALSE;
11019 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
11020
11021 if (rt != NULL) {
11022 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
11023 } else {
11024 is_local = necp_is_route_local(remote, include_local_addresses);
11025 }
11026 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);
11027 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11028 if (is_local) {
11029 // Match local-networks, fail
11030 return FALSE;
11031 }
11032 } else {
11033 if (!is_local) {
11034 // Either no route to validate or no match for local networks
11035 return FALSE;
11036 }
11037 }
11038 }
11039
11040 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
11041 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11042 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
11043 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
11044 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11045 if (inRange) {
11046 return FALSE;
11047 }
11048 } else {
11049 if (!inRange) {
11050 return FALSE;
11051 }
11052 }
11053 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11054 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
11055 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
11056 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11057 if (inSubnet) {
11058 return FALSE;
11059 }
11060 } else {
11061 if (!inSubnet) {
11062 return FALSE;
11063 }
11064 }
11065 }
11066 }
11067
11068 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
11069 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11070 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
11071 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
11072 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11073 if (inRange) {
11074 return FALSE;
11075 }
11076 } else {
11077 if (!inRange) {
11078 return FALSE;
11079 }
11080 }
11081 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11082 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
11083 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
11084 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11085 if (inSubnet) {
11086 return FALSE;
11087 }
11088 } else {
11089 if (!inSubnet) {
11090 return FALSE;
11091 }
11092 }
11093 }
11094 }
11095
11096 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11097 u_int16_t remote_port = 0;
11098 if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
11099 remote_port = SIN(remote)->sin_port;
11100 }
11101 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
11102 "NECP_KERNEL_CONDITION_SCHEME_PORT",
11103 0, remote_port);
11104 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11105 if (kernel_policy->cond_scheme_port == remote_port) {
11106 return FALSE;
11107 }
11108 } else {
11109 if (kernel_policy->cond_scheme_port != remote_port) {
11110 return FALSE;
11111 }
11112 }
11113 }
11114
11115 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11116 bool tags_matched = false;
11117 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
11118 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
11119 kernel_policy->cond_packet_filter_tags, pf_tag);
11120 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
11121 if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
11122 tags_matched = true;
11123 }
11124
11125 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11126 if (tags_matched) {
11127 return FALSE;
11128 }
11129 } else {
11130 if (!tags_matched) {
11131 return FALSE;
11132 }
11133 }
11134 }
11135 }
11136
11137 return TRUE;
11138 }
11139
11140 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)11141 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)
11142 {
11143 u_int32_t skip_order = 0;
11144 u_int32_t skip_session_order = 0;
11145 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11146 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)];
11147 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11148 size_t route_rule_id_count = 0;
11149 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11150 if (return_drop_all_bypass != NULL) {
11151 *return_drop_all_bypass = drop_all_bypass;
11152 }
11153
11154 if (return_route_rule_id != NULL) {
11155 *return_route_rule_id = 0;
11156 }
11157
11158 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11159
11160 if (policy_search_array != NULL) {
11161 for (int i = 0; policy_search_array[i] != NULL; i++) {
11162 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
11163 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
11164 // We've hit a drop all rule
11165 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11166 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11167 if (return_drop_all_bypass != NULL) {
11168 *return_drop_all_bypass = drop_all_bypass;
11169 }
11170 }
11171 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11172 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
11173 break;
11174 }
11175 }
11176 if (necp_drop_dest_policy.entry_count > 0 &&
11177 necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
11178 // We've hit a drop by destination address rule
11179 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
11180 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
11181 break;
11182 }
11183 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
11184 // Done skipping
11185 skip_order = 0;
11186 skip_session_order = 0;
11187 }
11188 if (skip_order) {
11189 if (policy_search_array[i]->order < skip_order) {
11190 // Skip this policy
11191 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
11192 continue;
11193 } else {
11194 // Done skipping
11195 skip_order = 0;
11196 skip_session_order = 0;
11197 }
11198 } else if (skip_session_order) {
11199 // Skip this policy
11200 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
11201 continue;
11202 }
11203
11204 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)) {
11205 if (!debug && necp_data_tracing_session_order) {
11206 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
11207 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
11208 NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
11209 }
11210 }
11211
11212 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
11213 if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
11214 route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
11215 }
11216 continue;
11217 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
11218 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
11219 skip_session_order = policy_search_array[i]->session_order + 1;
11220 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
11221 continue;
11222 }
11223
11224 // Passed all tests, found a match
11225 matched_policy = policy_search_array[i];
11226 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
11227 break;
11228 }
11229 }
11230 }
11231
11232 if (route_rule_id_count == 1) {
11233 *return_route_rule_id = route_rule_id_array[0];
11234 } else if (route_rule_id_count > 1) {
11235 *return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11236 }
11237
11238 return matched_policy;
11239 }
11240
11241 static inline bool
necp_output_bypass(struct mbuf * packet)11242 necp_output_bypass(struct mbuf *packet)
11243 {
11244 if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
11245 return true;
11246 }
11247 if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
11248 return true;
11249 }
11250 if (necp_is_intcoproc(NULL, packet)) {
11251 return true;
11252 }
11253 return false;
11254 }
11255
11256 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)11257 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
11258 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11259 {
11260 struct ip *ip = NULL;
11261 int hlen = sizeof(struct ip);
11262 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11263 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11264 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11265 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11266 u_int16_t protocol = 0;
11267 u_int32_t bound_interface_index = 0;
11268 u_int32_t last_interface_index = 0;
11269 union necp_sockaddr_union local_addr = { };
11270 union necp_sockaddr_union remote_addr = { };
11271 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11272 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11273 u_int16_t pf_tag = 0;
11274
11275 if (result) {
11276 *result = 0;
11277 }
11278
11279 if (result_parameter) {
11280 memset(result_parameter, 0, sizeof(*result_parameter));
11281 }
11282
11283 if (packet == NULL) {
11284 return NECP_KERNEL_POLICY_ID_NONE;
11285 }
11286
11287 socket_policy_id = necp_get_policy_id_from_packet(packet);
11288 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11289 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11290
11291 // Exit early for an empty list
11292 // Don't lock. Possible race condition, but we don't want the performance hit.
11293 if (necp_kernel_ip_output_policies_count == 0 ||
11294 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
11295 if (necp_drop_all_order > 0) {
11296 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11297 if (result) {
11298 if (necp_output_bypass(packet)) {
11299 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11300 } else {
11301 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11302 }
11303 }
11304 }
11305
11306 return matched_policy_id;
11307 }
11308
11309 // Check for loopback exception
11310 if (necp_output_bypass(packet)) {
11311 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11312 if (result) {
11313 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11314 }
11315 return matched_policy_id;
11316 }
11317
11318 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11319
11320 // Process packet to get relevant fields
11321 ip = mtod(packet, struct ip *);
11322 #ifdef _IP_VHL
11323 hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
11324 #else
11325 hlen = ip->ip_hl << 2;
11326 #endif
11327
11328 protocol = ip->ip_p;
11329
11330 if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
11331 (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
11332 ipoa->ipoa_boundif != IFSCOPE_NONE) {
11333 bound_interface_index = ipoa->ipoa_boundif;
11334 }
11335
11336 local_addr.sin.sin_family = AF_INET;
11337 local_addr.sin.sin_len = sizeof(struct sockaddr_in);
11338 memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
11339
11340 remote_addr.sin.sin_family = AF_INET;
11341 remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
11342 memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
11343
11344 switch (protocol) {
11345 case IPPROTO_TCP: {
11346 struct tcphdr th;
11347 if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
11348 m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
11349 SIN(&local_addr)->sin_port = th.th_sport;
11350 SIN(&remote_addr)->sin_port = th.th_dport;
11351 }
11352 break;
11353 }
11354 case IPPROTO_UDP: {
11355 struct udphdr uh;
11356 if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
11357 m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
11358 SIN(&local_addr)->sin_port = uh.uh_sport;
11359 SIN(&remote_addr)->sin_port = uh.uh_dport;
11360 }
11361 break;
11362 }
11363 default: {
11364 SIN(&local_addr)->sin_port = 0;
11365 SIN(&remote_addr)->sin_port = 0;
11366 break;
11367 }
11368 }
11369
11370 // Match packet to policy
11371 lck_rw_lock_shared(&necp_kernel_policy_lock);
11372 u_int32_t route_rule_id = 0;
11373
11374 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11375 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
11376
11377 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);
11378 if (matched_policy) {
11379 matched_policy_id = matched_policy->id;
11380 if (result) {
11381 *result = matched_policy->result;
11382 }
11383
11384 if (result_parameter) {
11385 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11386 }
11387
11388 if (route_rule_id != 0 &&
11389 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11390 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11391 }
11392
11393 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11394 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);
11395 }
11396 } else {
11397 bool drop_all = false;
11398 /*
11399 * Apply drop-all only to packets which have never matched a primary policy (check
11400 * if the packet saved policy id is none or falls within the socket policy id range).
11401 */
11402 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11403 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11404 drop_all = true;
11405 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11406 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11407 }
11408 }
11409 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11410 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11411 if (result) {
11412 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11413 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
11414 }
11415 } else if (route_rule_id != 0 &&
11416 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11417 // If we matched a route rule, mark it
11418 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11419 }
11420 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11421 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);
11422 }
11423 }
11424
11425 lck_rw_done(&necp_kernel_policy_lock);
11426
11427 return matched_policy_id;
11428 }
11429
11430 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)11431 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11432 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11433 {
11434 struct ip6_hdr *ip6 = NULL;
11435 int next = -1;
11436 int offset = 0;
11437 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11438 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11439 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11440 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11441 u_int16_t protocol = 0;
11442 u_int32_t bound_interface_index = 0;
11443 u_int32_t last_interface_index = 0;
11444 union necp_sockaddr_union local_addr = { };
11445 union necp_sockaddr_union remote_addr = { };
11446 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11447 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11448 u_int16_t pf_tag = 0;
11449
11450 if (result) {
11451 *result = 0;
11452 }
11453
11454 if (result_parameter) {
11455 memset(result_parameter, 0, sizeof(*result_parameter));
11456 }
11457
11458 if (packet == NULL) {
11459 return NECP_KERNEL_POLICY_ID_NONE;
11460 }
11461
11462 socket_policy_id = necp_get_policy_id_from_packet(packet);
11463 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11464 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11465
11466 // Exit early for an empty list
11467 // Don't lock. Possible race condition, but we don't want the performance hit.
11468 if (necp_drop_management_order == 0 &&
11469 (necp_kernel_ip_output_policies_count == 0 ||
11470 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11471 if (necp_drop_all_order > 0) {
11472 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11473 if (result) {
11474 if (necp_output_bypass(packet)) {
11475 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11476 } else {
11477 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11478 }
11479 }
11480 }
11481
11482 return matched_policy_id;
11483 }
11484
11485 // Check for loopback exception
11486 if (necp_output_bypass(packet)) {
11487 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11488 if (result) {
11489 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11490 }
11491 return matched_policy_id;
11492 }
11493
11494 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11495
11496 // Process packet to get relevant fields
11497 ip6 = mtod(packet, struct ip6_hdr *);
11498
11499 if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11500 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11501 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11502 bound_interface_index = ip6oa->ip6oa_boundif;
11503 }
11504
11505 SIN6(&local_addr)->sin6_family = AF_INET6;
11506 SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11507 memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11508
11509 SIN6(&remote_addr)->sin6_family = AF_INET6;
11510 SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11511 memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11512
11513 offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11514 if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11515 protocol = next;
11516 switch (protocol) {
11517 case IPPROTO_TCP: {
11518 struct tcphdr th;
11519 if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11520 m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11521 SIN6(&local_addr)->sin6_port = th.th_sport;
11522 SIN6(&remote_addr)->sin6_port = th.th_dport;
11523 }
11524 break;
11525 }
11526 case IPPROTO_UDP: {
11527 struct udphdr uh;
11528 if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11529 m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11530 SIN6(&local_addr)->sin6_port = uh.uh_sport;
11531 SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11532 }
11533 break;
11534 }
11535 default: {
11536 SIN6(&local_addr)->sin6_port = 0;
11537 SIN6(&remote_addr)->sin6_port = 0;
11538 break;
11539 }
11540 }
11541 }
11542
11543 // Match packet to policy
11544 lck_rw_lock_shared(&necp_kernel_policy_lock);
11545 u_int32_t route_rule_id = 0;
11546
11547 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11548 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11549
11550 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);
11551 if (matched_policy) {
11552 matched_policy_id = matched_policy->id;
11553 if (result) {
11554 *result = matched_policy->result;
11555 }
11556
11557 if (result_parameter) {
11558 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11559 }
11560
11561 if (route_rule_id != 0 &&
11562 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11563 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11564 }
11565
11566 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11567 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);
11568 }
11569 } else {
11570 bool drop_all = false;
11571 /*
11572 * Apply drop-all only to packets which have never matched a primary policy (check
11573 * if the packet saved policy id is none or falls within the socket policy id range).
11574 */
11575 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11576 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11577 drop_all = true;
11578 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11579 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11580 }
11581 }
11582 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11583 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11584 if (result) {
11585 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11586 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11587 }
11588 } else if (route_rule_id != 0 &&
11589 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11590 // If we matched a route rule, mark it
11591 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11592 }
11593 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11594 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);
11595 }
11596 }
11597
11598 lck_rw_done(&necp_kernel_policy_lock);
11599
11600 return matched_policy_id;
11601 }
11602
11603 // Utilities
11604 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11605 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11606 {
11607 int cmp = 0;
11608
11609 if (addr == NULL || range_start == NULL || range_end == NULL) {
11610 return FALSE;
11611 }
11612
11613 /* Must be greater than or equal to start */
11614 cmp = necp_addr_compare(addr, range_start, 1);
11615 if (cmp != 0 && cmp != 1) {
11616 return FALSE;
11617 }
11618
11619 /* Must be less than or equal to end */
11620 cmp = necp_addr_compare(addr, range_end, 1);
11621 if (cmp != 0 && cmp != -1) {
11622 return FALSE;
11623 }
11624
11625 return TRUE;
11626 }
11627
11628 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)11629 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11630 {
11631 int cmp = 0;
11632
11633 if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11634 return FALSE;
11635 }
11636
11637 /* Must be greater than or equal to start */
11638 cmp = necp_addr_compare(inner_range_start, range_start, 1);
11639 if (cmp != 0 && cmp != 1) {
11640 return FALSE;
11641 }
11642
11643 /* Must be less than or equal to end */
11644 cmp = necp_addr_compare(inner_range_end, range_end, 1);
11645 if (cmp != 0 && cmp != -1) {
11646 return FALSE;
11647 }
11648
11649 return TRUE;
11650 }
11651
11652 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11653 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11654 {
11655 if (addr == NULL || subnet_addr == NULL) {
11656 return FALSE;
11657 }
11658
11659 if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11660 return FALSE;
11661 }
11662
11663 switch (addr->sa_family) {
11664 case AF_INET: {
11665 if (satosin(subnet_addr)->sin_port != 0 &&
11666 satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11667 return FALSE;
11668 }
11669 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11670 }
11671 case AF_INET6: {
11672 if (satosin6(subnet_addr)->sin6_port != 0 &&
11673 satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11674 return FALSE;
11675 }
11676 if (satosin6(addr)->sin6_scope_id &&
11677 satosin6(subnet_addr)->sin6_scope_id &&
11678 satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11679 return FALSE;
11680 }
11681 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11682 }
11683 default: {
11684 return FALSE;
11685 }
11686 }
11687
11688 return FALSE;
11689 }
11690
11691 /*
11692 * Return values:
11693 * -1: sa1 < sa2
11694 * 0: sa1 == sa2
11695 * 1: sa1 > sa2
11696 * 2: Not comparable or error
11697 */
11698 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11699 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11700 {
11701 int result = 0;
11702 int port_result = 0;
11703
11704 if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11705 return 2;
11706 }
11707
11708 if (sa1->sa_len == 0) {
11709 return 0;
11710 }
11711
11712 switch (sa1->sa_family) {
11713 case AF_INET: {
11714 if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11715 return 2;
11716 }
11717
11718 result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11719
11720 if (check_port) {
11721 if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11722 port_result = -1;
11723 } else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11724 port_result = 1;
11725 }
11726
11727 if (result == 0) {
11728 result = port_result;
11729 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11730 return 2;
11731 }
11732 }
11733
11734 break;
11735 }
11736 case AF_INET6: {
11737 if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11738 return 2;
11739 }
11740
11741 if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11742 return 2;
11743 }
11744
11745 result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11746
11747 if (check_port) {
11748 if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11749 port_result = -1;
11750 } else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11751 port_result = 1;
11752 }
11753
11754 if (result == 0) {
11755 result = port_result;
11756 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11757 return 2;
11758 }
11759 }
11760
11761 break;
11762 }
11763 default: {
11764 result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11765 break;
11766 }
11767 }
11768
11769 if (result < 0) {
11770 result = (-1);
11771 } else if (result > 0) {
11772 result = (1);
11773 }
11774
11775 return result;
11776 }
11777
11778 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11779 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11780 {
11781 u_int8_t mask;
11782
11783 /* Handle null pointers */
11784 if (p1 == NULL || p2 == NULL) {
11785 return p1 == p2;
11786 }
11787
11788 while (bits >= 8) {
11789 if (*p1++ != *p2++) {
11790 return FALSE;
11791 }
11792 bits -= 8;
11793 }
11794
11795 if (bits > 0) {
11796 mask = ~((1 << (8 - bits)) - 1);
11797 if ((*p1 & mask) != (*p2 & mask)) {
11798 return FALSE;
11799 }
11800 }
11801 return TRUE;
11802 }
11803
11804 static bool
necp_addr_is_empty(struct sockaddr * addr)11805 necp_addr_is_empty(struct sockaddr *addr)
11806 {
11807 if (addr == NULL) {
11808 return TRUE;
11809 }
11810
11811 if (addr->sa_len == 0) {
11812 return TRUE;
11813 }
11814
11815 switch (addr->sa_family) {
11816 case AF_INET: {
11817 static struct sockaddr_in ipv4_empty_address = {
11818 .sin_len = sizeof(struct sockaddr_in),
11819 .sin_family = AF_INET,
11820 .sin_port = 0,
11821 .sin_addr = { .s_addr = 0 }, // 0.0.0.0
11822 .sin_zero = {0},
11823 };
11824 if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11825 return TRUE;
11826 } else {
11827 return FALSE;
11828 }
11829 }
11830 case AF_INET6: {
11831 static struct sockaddr_in6 ipv6_empty_address = {
11832 .sin6_len = sizeof(struct sockaddr_in6),
11833 .sin6_family = AF_INET6,
11834 .sin6_port = 0,
11835 .sin6_flowinfo = 0,
11836 .sin6_addr = IN6ADDR_ANY_INIT, // ::
11837 .sin6_scope_id = 0,
11838 };
11839 if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11840 return TRUE;
11841 } else {
11842 return FALSE;
11843 }
11844 }
11845 default:
11846 return FALSE;
11847 }
11848
11849 return FALSE;
11850 }
11851
11852 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)11853 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)
11854 {
11855 bool qos_marking = FALSE;
11856 int exception_index = 0;
11857 struct necp_route_rule *route_rule = NULL;
11858
11859 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11860 if (route_rule == NULL) {
11861 qos_marking = FALSE;
11862 goto done;
11863 }
11864
11865 if (route_rule->match_netagent_id != 0) {
11866 if (netagent_array == NULL || netagent_array_count == 0) {
11867 // No agents, ignore rule
11868 goto done;
11869 }
11870 bool found_match = FALSE;
11871 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11872 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11873 found_match = TRUE;
11874 break;
11875 }
11876 }
11877 if (!found_match) {
11878 // Agents don't match, ignore rule
11879 goto done;
11880 }
11881 }
11882
11883 qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11884
11885 if (ifp == NULL) {
11886 goto done;
11887 }
11888
11889 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11890 if (route_rule->exception_if_indices[exception_index] == 0) {
11891 break;
11892 }
11893 if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
11894 continue;
11895 }
11896 if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
11897 qos_marking = TRUE;
11898 if (necp_debug > 2) {
11899 NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
11900 route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
11901 }
11902 goto done;
11903 }
11904 }
11905
11906 if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
11907 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
11908 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
11909 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
11910 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
11911 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
11912 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
11913 qos_marking = TRUE;
11914 if (necp_debug > 2) {
11915 NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d for Rule %d Allowed %d",
11916 route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
11917 route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action, route_rule_id, qos_marking);
11918 }
11919 goto done;
11920 }
11921 done:
11922 if (necp_debug > 1) {
11923 NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
11924 route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
11925 }
11926 return qos_marking;
11927 }
11928
11929 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)11930 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)
11931 {
11932 bool new_qos_marking = old_qos_marking;
11933 struct ifnet *ifp = interface;
11934
11935 if (net_qos_policy_restricted == 0) {
11936 return new_qos_marking;
11937 }
11938
11939 /*
11940 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
11941 */
11942 if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
11943 return new_qos_marking;
11944 }
11945
11946 lck_rw_lock_shared(&necp_kernel_policy_lock);
11947
11948 if (ifp == NULL && route != NULL) {
11949 ifp = route->rt_ifp;
11950 }
11951 /*
11952 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
11953 */
11954 if (ifp == NULL || route_rule_id == 0) {
11955 new_qos_marking = FALSE;
11956 goto done;
11957 }
11958
11959 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11960 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11961 if (aggregate_route_rule != NULL) {
11962 int index = 0;
11963 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11964 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11965 if (sub_route_rule_id == 0) {
11966 break;
11967 }
11968 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
11969 if (new_qos_marking == TRUE) {
11970 break;
11971 }
11972 }
11973 }
11974 } else {
11975 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
11976 }
11977 /*
11978 * Now that we have an interface we remember the gencount
11979 */
11980 *qos_marking_gencount = necp_kernel_socket_policies_gencount;
11981
11982 done:
11983 lck_rw_done(&necp_kernel_policy_lock);
11984 return new_qos_marking;
11985 }
11986
11987 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)11988 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11989 {
11990 bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11991
11992 if (net_qos_policy_restricted == 0) {
11993 return;
11994 }
11995 if (inp->inp_socket == NULL) {
11996 return;
11997 }
11998 if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11999 return;
12000 }
12001
12002 qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
12003
12004 if (qos_marking == TRUE) {
12005 inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
12006 } else {
12007 inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
12008 }
12009 }
12010
12011 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)12012 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
12013 {
12014 if (ifp != NULL &&
12015 (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12016 ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12017 return true;
12018 }
12019 if (delegated_ifp != NULL &&
12020 (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12021 delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12022 return true;
12023 }
12024 return false;
12025 }
12026
12027 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)12028 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,
12029 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12030 {
12031 bool default_is_allowed = TRUE;
12032 u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
12033 int exception_index = 0;
12034 struct ifnet *delegated_ifp = NULL;
12035 struct necp_route_rule *route_rule = NULL;
12036
12037 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12038 if (route_rule == NULL) {
12039 return TRUE;
12040 }
12041
12042 if (route_rule->match_netagent_id != 0) {
12043 if (netagent_array == NULL || netagent_array_count == 0) {
12044 // No agents, ignore rule
12045 return TRUE;
12046 }
12047 bool found_match = FALSE;
12048 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12049 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12050 found_match = TRUE;
12051 break;
12052 }
12053 }
12054 if (!found_match) {
12055 // Agents don't match, ignore rule
12056 return TRUE;
12057 }
12058 }
12059
12060 default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
12061 if (ifp == NULL && route != NULL) {
12062 ifp = route->rt_ifp;
12063 }
12064 if (ifp == NULL) {
12065 if (necp_debug > 1 && !default_is_allowed) {
12066 NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12067 }
12068 return default_is_allowed;
12069 }
12070
12071 delegated_ifp = ifp->if_delegated.ifp;
12072 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12073 if (route_rule->exception_if_indices[exception_index] == 0) {
12074 break;
12075 }
12076 if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
12077 (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
12078 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12079 const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
12080 if (necp_debug > 1 && lqm_abort) {
12081 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
12082 route_rule->exception_if_indices[exception_index], route_rule_id);
12083 }
12084 return false;
12085 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
12086 if (necp_debug > 1) {
12087 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));
12088 }
12089 if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
12090 *interface_type_denied = route_rule->effective_type;
12091 }
12092 return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
12093 }
12094 }
12095 }
12096
12097 if (IFNET_IS_CELLULAR(ifp)) {
12098 if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12099 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12100 if (interface_type_denied != NULL) {
12101 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12102 if (route_rule->effective_type != 0) {
12103 *interface_type_denied = route_rule->effective_type;
12104 }
12105 }
12106 // Mark aggregate action as deny
12107 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12108 }
12109 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
12110 if (interface_type_denied != NULL) {
12111 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12112 if (route_rule->effective_type != 0) {
12113 *interface_type_denied = route_rule->effective_type;
12114 }
12115 }
12116 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12117 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12118 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
12119 // Deny wins if there is a conflict
12120 type_aggregate_action = route_rule->cellular_action;
12121 }
12122 }
12123 }
12124
12125 if (IFNET_IS_WIFI(ifp)) {
12126 if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12127 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12128 if (interface_type_denied != NULL) {
12129 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12130 if (route_rule->effective_type != 0) {
12131 *interface_type_denied = route_rule->effective_type;
12132 }
12133 }
12134 // Mark aggregate action as deny
12135 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12136 }
12137 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
12138 if (interface_type_denied != NULL) {
12139 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12140 if (route_rule->effective_type != 0) {
12141 *interface_type_denied = route_rule->effective_type;
12142 }
12143 }
12144 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12145 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12146 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
12147 // Deny wins if there is a conflict
12148 type_aggregate_action = route_rule->wifi_action;
12149 }
12150 }
12151 }
12152
12153 if (IFNET_IS_COMPANION_LINK(ifp) ||
12154 (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
12155 if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12156 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12157 if (interface_type_denied != NULL) {
12158 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12159 if (route_rule->effective_type != 0) {
12160 *interface_type_denied = route_rule->effective_type;
12161 }
12162 }
12163 // Mark aggregate action as deny
12164 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12165 }
12166 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
12167 if (interface_type_denied != NULL) {
12168 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12169 if (route_rule->effective_type != 0) {
12170 *interface_type_denied = route_rule->effective_type;
12171 }
12172 }
12173 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12174 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12175 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
12176 // Deny wins if there is a conflict
12177 type_aggregate_action = route_rule->companion_action;
12178 }
12179 }
12180 }
12181
12182 if (IFNET_IS_WIRED(ifp)) {
12183 if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12184 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12185 if (interface_type_denied != NULL) {
12186 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12187 if (route_rule->effective_type != 0) {
12188 *interface_type_denied = route_rule->effective_type;
12189 }
12190 }
12191 // Mark aggregate action as deny
12192 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12193 }
12194 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
12195 if (interface_type_denied != NULL) {
12196 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12197 if (route_rule->effective_type != 0) {
12198 *interface_type_denied = route_rule->effective_type;
12199 }
12200 }
12201 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12202 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12203 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
12204 // Deny wins if there is a conflict
12205 type_aggregate_action = route_rule->wired_action;
12206 }
12207 }
12208 }
12209
12210 if (IFNET_IS_EXPENSIVE(ifp)) {
12211 if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12212 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12213 // Mark aggregate action as deny
12214 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12215 }
12216 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
12217 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12218 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12219 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
12220 // Deny wins if there is a conflict
12221 type_aggregate_action = route_rule->expensive_action;
12222 }
12223 }
12224 }
12225
12226 if (IFNET_IS_CONSTRAINED(ifp)) {
12227 if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12228 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12229 // Mark aggregate action as deny
12230 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12231 }
12232 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
12233 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12234 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12235 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
12236 // Deny wins if there is a conflict
12237 type_aggregate_action = route_rule->constrained_action;
12238 }
12239 }
12240 }
12241
12242 if (IFNET_IS_VPN(ifp)) {
12243 if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12244 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12245 // Mark aggregate action as deny
12246 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12247 }
12248 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
12249 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12250 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12251 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
12252 // Deny wins if there is a conflict
12253 type_aggregate_action = route_rule->vpn_action;
12254 }
12255 }
12256 }
12257
12258 if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
12259 if (necp_debug > 1) {
12260 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));
12261 }
12262 return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
12263 }
12264
12265 if (necp_debug > 1 && !default_is_allowed) {
12266 NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12267 }
12268 return default_is_allowed;
12269 }
12270
12271 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)12272 necp_proc_is_allowed_on_management_interface(proc_t proc)
12273 {
12274 bool allowed = false;
12275 const task_t __single task = proc_task(proc);
12276
12277 if (task != NULL) {
12278 if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
12279 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
12280 #if DEBUG || DEVELOPMENT
12281 || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
12282 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
12283 #endif /* DEBUG || DEVELOPMENT */
12284 ) {
12285 allowed = true;
12286 }
12287 }
12288 return allowed;
12289 }
12290
12291 __attribute__((noinline))
12292 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)12293 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12294 {
12295 char buf[128];
12296
12297 if (inp != NULL) {
12298 inp_snprintf_tuple(inp, buf, sizeof(buf));
12299 } else {
12300 *buf = 0;
12301 }
12302 os_log(OS_LOG_DEFAULT,
12303 "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
12304 proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
12305 proc != NULL ? proc_getpid(proc) : proc_selfpid(),
12306 inp != NULL ? buf : "",
12307 ifp->if_xname);
12308 }
12309
12310 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)12311 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12312 {
12313 if (if_management_interface_check_needed == false) {
12314 return true;
12315 }
12316 if (necp_drop_management_order == 0) {
12317 return true;
12318 }
12319 if (ifp == NULL && route != NULL) {
12320 ifp = route->rt_ifp;
12321 }
12322 if (ifp == NULL) {
12323 return true;
12324 }
12325
12326 if (IFNET_IS_MANAGEMENT(ifp)) {
12327 bool allowed = true;
12328
12329 if (inp != NULL) {
12330 /*
12331 * The entitlement check is already performed for socket flows
12332 */
12333 allowed = INP_MANAGEMENT_ALLOWED(inp);
12334 } else if (proc != NULL) {
12335 allowed = necp_proc_is_allowed_on_management_interface(proc);
12336 }
12337 if (__improbable(if_management_verbose > 1 && allowed == false)) {
12338 necp_log_interface_not_allowed(ifp, proc, inp);
12339 }
12340 return allowed;
12341 }
12342 return true;
12343 }
12344
12345 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)12346 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,
12347 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12348 {
12349 if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
12350 if (necp_debug > 1) {
12351 NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
12352 }
12353 return TRUE;
12354 }
12355
12356 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12357 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12358 if (aggregate_route_rule != NULL) {
12359 int index = 0;
12360 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12361 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12362 if (sub_route_rule_id == 0) {
12363 break;
12364 }
12365 if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
12366 return FALSE;
12367 }
12368 }
12369 }
12370 } else {
12371 return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
12372 }
12373
12374 return TRUE;
12375 }
12376
12377 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)12378 necp_route_rule_matches_agents(u_int32_t route_rule_id)
12379 {
12380 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12381 if (route_rule == NULL) {
12382 return false;
12383 }
12384
12385 return route_rule->match_netagent_id != 0;
12386 }
12387
12388 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)12389 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)
12390 {
12391 if (remove == NULL) {
12392 return 0;
12393 }
12394
12395 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12396 if (route_rule == NULL) {
12397 return 0;
12398 }
12399
12400 // No netagent, skip
12401 if (route_rule->netagent_id == 0) {
12402 return 0;
12403 }
12404
12405 if (route_rule->match_netagent_id != 0) {
12406 if (netagent_array == NULL || netagent_array_count == 0) {
12407 // No agents, ignore rule
12408 return 0;
12409 }
12410 bool found_match = FALSE;
12411 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12412 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12413 found_match = TRUE;
12414 break;
12415 }
12416 }
12417 if (!found_match) {
12418 // Agents don't match, ignore rule
12419 return 0;
12420 }
12421 }
12422
12423 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12424 if (ifp == NULL) {
12425 // No interface, apply the default action
12426 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12427 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12428 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12429 return route_rule->netagent_id;
12430 }
12431 return 0;
12432 }
12433
12434 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12435 if (route_rule->exception_if_indices[exception_index] == 0) {
12436 break;
12437 }
12438 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12439 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12440 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12441 route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12442 *remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12443 return route_rule->netagent_id;
12444 }
12445 return 0;
12446 }
12447 }
12448
12449 if (ifp->if_type == IFT_CELLULAR &&
12450 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12451 if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12452 route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12453 *remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12454 return route_rule->netagent_id;
12455 }
12456 return 0;
12457 }
12458
12459 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12460 route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12461 if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12462 route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12463 *remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12464 return route_rule->netagent_id;
12465 }
12466 return 0;
12467 }
12468
12469 if (IFNET_IS_COMPANION_LINK(ifp) &&
12470 route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12471 if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12472 route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12473 *remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12474 return route_rule->netagent_id;
12475 }
12476 return 0;
12477 }
12478
12479 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12480 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12481 if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12482 route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12483 *remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12484 return route_rule->netagent_id;
12485 }
12486 return 0;
12487 }
12488
12489 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12490 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12491 if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12492 route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12493 *remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12494 return route_rule->netagent_id;
12495 }
12496 return 0;
12497 }
12498
12499 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12500 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12501 if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12502 route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12503 *remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12504 return route_rule->netagent_id;
12505 }
12506 return 0;
12507 }
12508
12509 if (ifp->if_xflags & IFXF_IS_VPN &&
12510 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12511 if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12512 route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12513 *remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12514 return route_rule->netagent_id;
12515 }
12516 return 0;
12517 }
12518
12519 // No more specific case matched, apply the default action
12520 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12521 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12522 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12523 return route_rule->netagent_id;
12524 }
12525
12526 return 0;
12527 }
12528
12529 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)12530 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)
12531 {
12532 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12533 if (route_rule == NULL) {
12534 return 0;
12535 }
12536
12537 // No control unit, skip
12538 if (route_rule->control_unit == 0) {
12539 return 0;
12540 }
12541
12542 if (route_rule->match_netagent_id != 0) {
12543 if (netagent_array == NULL || netagent_array_count == 0) {
12544 // No agents, ignore rule
12545 return 0;
12546 }
12547 bool found_match = FALSE;
12548 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12549 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12550 found_match = TRUE;
12551 break;
12552 }
12553 }
12554 if (!found_match) {
12555 // Agents don't match, ignore rule
12556 return 0;
12557 }
12558 }
12559
12560 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12561 if (ifp == NULL) {
12562 // No interface, apply the default action
12563 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12564 return route_rule->control_unit;
12565 }
12566 return 0;
12567 }
12568
12569 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12570 if (route_rule->exception_if_indices[exception_index] == 0) {
12571 break;
12572 }
12573 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12574 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12575 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12576 return route_rule->control_unit;
12577 }
12578 return 0;
12579 }
12580 }
12581
12582 if (ifp->if_type == IFT_CELLULAR &&
12583 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12584 if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12585 return route_rule->control_unit;
12586 }
12587 return 0;
12588 }
12589
12590 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12591 route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12592 if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12593 return route_rule->control_unit;
12594 }
12595 return 0;
12596 }
12597
12598 if (IFNET_IS_COMPANION_LINK(ifp) &&
12599 route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12600 if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12601 return route_rule->control_unit;
12602 }
12603 return 0;
12604 }
12605
12606 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12607 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12608 if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12609 return route_rule->control_unit;
12610 }
12611 return 0;
12612 }
12613
12614 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12615 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12616 if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12617 return route_rule->control_unit;
12618 }
12619 return 0;
12620 }
12621
12622 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12623 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12624 if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12625 return route_rule->control_unit;
12626 }
12627 return 0;
12628 }
12629
12630 if (ifp->if_xflags & IFXF_IS_VPN &&
12631 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12632 if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12633 return route_rule->control_unit;
12634 }
12635 return 0;
12636 }
12637
12638 // No more specific case matched, apply the default action
12639 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12640 return route_rule->control_unit;
12641 }
12642 return 0;
12643 }
12644
12645 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)12646 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,
12647 u_int32_t *flow_divert_aggregate_unit)
12648 {
12649 if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12650 return 0;
12651 }
12652
12653 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12654 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12655 if (aggregate_route_rule != NULL) {
12656 int index = 0;
12657 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12658 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12659 if (sub_route_rule_id == 0) {
12660 break;
12661 }
12662 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12663 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12664 // For transparent proxies, accumulate the control unit and continue to the next route rule
12665 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12666 continue;
12667 }
12668
12669 if (control_unit != 0) {
12670 return control_unit;
12671 }
12672 }
12673 }
12674 } else {
12675 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12676 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12677 // For transparent proxies, accumulate the control unit and let the caller continue
12678 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12679 return 0;
12680 }
12681 return control_unit;
12682 }
12683
12684 return 0;
12685 }
12686
12687 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12688 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12689 {
12690 bool is_allowed = true;
12691 u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12692 if (route_rule_id != 0 &&
12693 interface != NULL) {
12694 lck_rw_lock_shared(&necp_kernel_policy_lock);
12695 is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
12696 lck_rw_done(&necp_kernel_policy_lock);
12697 }
12698 return is_allowed;
12699 }
12700
12701 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12702 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12703 {
12704 size_t netagent_cursor;
12705 for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12706 struct necp_uuid_id_mapping *mapping = NULL;
12707 u_int32_t netagent_id = netagent_ids[netagent_cursor];
12708 if (netagent_id == 0) {
12709 continue;
12710 }
12711 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
12712 if (mapping != NULL) {
12713 u_int32_t agent_flags = 0;
12714 agent_flags = netagent_get_flags(mapping->uuid);
12715 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12716 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12717 continue;
12718 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12719 return FALSE;
12720 }
12721 }
12722 }
12723 }
12724 return TRUE;
12725 }
12726
12727 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12728 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12729 {
12730 bool allowed_to_receive = TRUE;
12731
12732 if (pf_tag == PF_TAG_ID_STACK_DROP &&
12733 (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12734 allowed_to_receive = FALSE;
12735 }
12736
12737 return allowed_to_receive;
12738 }
12739
12740 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)12741 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)
12742 {
12743 u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12744 bool allowed_to_receive = TRUE;
12745 struct necp_socket_info info = {};
12746 u_int32_t flowhash = 0;
12747 necp_kernel_policy_result service_action = 0;
12748 necp_kernel_policy_service service = { 0, 0 };
12749 u_int32_t route_rule_id = 0;
12750 struct rtentry *route = NULL;
12751 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12752 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12753 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12754 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12755 proc_t __single socket_proc = NULL;
12756 necp_kernel_policy_filter filter_control_unit = 0;
12757 u_int32_t pass_flags = 0;
12758 u_int32_t flow_divert_aggregate_unit = 0;
12759 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12760 int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12761
12762 memset(&netagent_ids, 0, sizeof(netagent_ids));
12763
12764 if (return_policy_id) {
12765 *return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12766 }
12767 if (return_skip_policy_id) {
12768 *return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12769 }
12770 if (return_route_rule_id) {
12771 *return_route_rule_id = 0;
12772 }
12773 if (return_pass_flags) {
12774 *return_pass_flags = 0;
12775 }
12776
12777 if (inp == NULL) {
12778 goto done;
12779 }
12780
12781 route = inp->inp_route.ro_rt;
12782
12783 struct socket *so = inp->inp_socket;
12784
12785 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12786
12787 // Don't lock. Possible race condition, but we don't want the performance hit.
12788 if (necp_drop_management_order == 0 &&
12789 (necp_kernel_socket_policies_count == 0 ||
12790 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12791 if (necp_drop_all_order > 0 || drop_order > 0) {
12792 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12793 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12794 allowed_to_receive = TRUE;
12795 } else {
12796 allowed_to_receive = FALSE;
12797 }
12798 }
12799 goto done;
12800 }
12801
12802 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
12803 if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12804 bool policies_have_changed = FALSE;
12805 bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12806 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12807 policies_have_changed = TRUE;
12808 } else {
12809 if (inp->inp_policyresult.results.route_rule_id != 0) {
12810 lck_rw_lock_shared(&necp_kernel_policy_lock);
12811 if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
12812 route_allowed = FALSE;
12813 }
12814 lck_rw_done(&necp_kernel_policy_lock);
12815 }
12816 }
12817
12818 if (!policies_have_changed) {
12819 if (debug) {
12820 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);
12821 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12822 }
12823
12824 if (!route_allowed ||
12825 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12826 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12827 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12828 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12829 allowed_to_receive = FALSE;
12830 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);
12831 } else {
12832 if (return_policy_id) {
12833 *return_policy_id = inp->inp_policyresult.policy_id;
12834 }
12835 if (return_skip_policy_id) {
12836 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12837 }
12838 if (return_route_rule_id) {
12839 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12840 }
12841 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12842 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12843 }
12844 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);
12845 }
12846 goto done;
12847 }
12848 }
12849
12850 // Check for loopback exception
12851 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12852 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12853 allowed_to_receive = FALSE;
12854 goto done;
12855 }
12856 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
12857 allowed_to_receive = TRUE;
12858 goto done;
12859 }
12860
12861 // Actually calculate policy result
12862 lck_rw_lock_shared(&necp_kernel_policy_lock);
12863 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);
12864
12865 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12866 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
12867
12868 flowhash = necp_socket_calc_flowhash_locked(&info);
12869 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12870 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
12871 inp->inp_policyresult.flowhash == flowhash) {
12872 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12873 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12874 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12875 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
12876 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12877 (inp->inp_policyresult.results.route_rule_id != 0 &&
12878 !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
12879 allowed_to_receive = FALSE;
12880 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);
12881 } else {
12882 if (return_policy_id) {
12883 *return_policy_id = inp->inp_policyresult.policy_id;
12884 }
12885 if (return_route_rule_id) {
12886 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12887 }
12888 if (return_skip_policy_id) {
12889 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12890 }
12891 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12892 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12893 }
12894 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12895 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",
12896 inp->inp_socket, info.bound_interface_index, info.protocol,
12897 inp->inp_policyresult.policy_id,
12898 inp->inp_policyresult.skip_policy_id,
12899 inp->inp_policyresult.results.result,
12900 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
12901 }
12902 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
12903 return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12904 }
12905 lck_rw_done(&necp_kernel_policy_lock);
12906 goto done;
12907 }
12908
12909 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
12910 size_t route_rule_id_array_count = 0;
12911 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
12912 struct necp_kernel_socket_policy *matched_policy =
12913 necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
12914 &info,
12915 &filter_control_unit,
12916 route_rule_id_array,
12917 &route_rule_id_array_count,
12918 MAX_AGGREGATE_ROUTE_RULES,
12919 &service_action,
12920 &service,
12921 netagent_ids,
12922 NECP_MAX_NETAGENTS,
12923 NULL,
12924 0,
12925 NULL,
12926 0,
12927 effective_proc,
12928 pf_tag,
12929 return_skip_policy_id,
12930 inp->inp_route.ro_rt,
12931 &drop_dest_policy_result,
12932 &drop_all_bypass,
12933 &flow_divert_aggregate_unit,
12934 so,
12935 debug);
12936
12937 // Check for loopback exception again after the policy match
12938 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
12939 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
12940 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
12941 // If policies haven't changed since last evaluation, do not update filter result in order to
12942 // preserve the very first filter result for the socket. Otherwise, update the filter result to
12943 // allow content filter to detect and drop pre-existing flows.
12944 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
12945 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
12946 if (info.soflow_entry != NULL) {
12947 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
12948 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
12949 }
12950 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
12951 current_filter_control_unit != filter_control_unit) {
12952 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12953 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12954 if (info.soflow_entry != NULL) {
12955 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
12956 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
12957 }
12958 }
12959 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12960 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12961 }
12962 allowed_to_receive = TRUE;
12963 lck_rw_done(&necp_kernel_policy_lock);
12964
12965 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);
12966 goto done;
12967 }
12968
12969 if (info.protocol != IPPROTO_UDP) {
12970 goto skip_agent_check;
12971 }
12972
12973 // Verify netagents
12974 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
12975 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12976 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);
12977 }
12978
12979 // Mark socket as a drop if required agent is not active
12980 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12981 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12982 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12983 inp->inp_policyresult.flowhash = flowhash;
12984 inp->inp_policyresult.results.filter_control_unit = 0;
12985 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
12986 inp->inp_policyresult.results.route_rule_id = 0;
12987 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
12988 if (info.soflow_entry != NULL) {
12989 info.soflow_entry->soflow_filter_control_unit = 0;
12990 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
12991 }
12992
12993 // Unlock
12994 allowed_to_receive = FALSE;
12995 lck_rw_done(&necp_kernel_policy_lock);
12996
12997 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);
12998
12999 goto done;
13000 }
13001
13002 skip_agent_check:
13003
13004 if (route_rule_id_array_count == 1) {
13005 route_rule_id = route_rule_id_array[0];
13006 } else if (route_rule_id_array_count > 1) {
13007 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
13008 }
13009
13010 bool send_local_network_denied_event = false;
13011 if (matched_policy != NULL) {
13012 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
13013 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
13014 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
13015 // Trigger the event that we dropped due to a local network policy
13016 send_local_network_denied_event = true;
13017 }
13018
13019 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
13020 matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13021 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13022 matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
13023 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13024 (route_rule_id != 0 &&
13025 !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
13026 !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
13027 allowed_to_receive = FALSE;
13028 } else {
13029 if (return_policy_id) {
13030 *return_policy_id = matched_policy->id;
13031 }
13032 if (return_route_rule_id) {
13033 *return_route_rule_id = route_rule_id;
13034 }
13035 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
13036 pass_flags = matched_policy->result_parameter.pass_flags;
13037 }
13038 // If policies haven't changed since last evaluation, do not update filter result in order to
13039 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13040 // allow content filter to detect and drop pre-existing flows.
13041 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13042 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13043 if (info.soflow_entry != NULL) {
13044 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13045 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13046 }
13047 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13048 current_filter_control_unit != filter_control_unit) {
13049 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13050 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13051 if (info.soflow_entry != NULL) {
13052 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13053 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13054 }
13055 }
13056 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13057 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13058 }
13059 }
13060
13061 if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
13062 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>",
13063 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);
13064 }
13065 } else {
13066 bool drop_all = false;
13067 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
13068 drop_all = true;
13069 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
13070 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
13071 }
13072 }
13073 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
13074 allowed_to_receive = FALSE;
13075 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
13076 } else {
13077 if (return_policy_id) {
13078 *return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13079 }
13080 if (return_route_rule_id) {
13081 *return_route_rule_id = route_rule_id;
13082 }
13083
13084 // If policies haven't changed since last evaluation, do not update filter result in order to
13085 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13086 // allow content filter to detect and drop pre-existing flows.
13087 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13088 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13089 if (info.soflow_entry != NULL) {
13090 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13091 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13092 }
13093 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13094 current_filter_control_unit != filter_control_unit) {
13095 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13096 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13097 if (info.soflow_entry != NULL) {
13098 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13099 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13100 }
13101 }
13102 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13103 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13104 }
13105 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);
13106 }
13107 }
13108
13109 if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
13110 allowed_to_receive = FALSE;
13111 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
13112 }
13113
13114 lck_rw_done(&necp_kernel_policy_lock);
13115
13116 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
13117 inp->inp_policyresult.network_denied_notifies++;
13118 #if defined(XNU_TARGET_OS_OSX)
13119 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
13120 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13121 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13122 NETPOLICY_NETWORKTYPE_LOCAL);
13123 #else
13124 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13125 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13126 NETPOLICY_NETWORKTYPE_LOCAL);
13127 #endif
13128 }
13129
13130 done:
13131 if (return_pass_flags != NULL) {
13132 *return_pass_flags = pass_flags;
13133 }
13134
13135 if (pf_tag != 0 && allowed_to_receive) {
13136 allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
13137 }
13138
13139 if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
13140 soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
13141 }
13142
13143 if (socket_proc) {
13144 proc_rele(socket_proc);
13145 }
13146
13147 if (info.soflow_entry != NULL) {
13148 soflow_free_flow(info.soflow_entry);
13149 }
13150
13151 return allowed_to_receive;
13152 }
13153
13154 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)13155 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)
13156 {
13157 struct sockaddr_in local = {};
13158 struct sockaddr_in remote = {};
13159 local.sin_family = remote.sin_family = AF_INET;
13160 local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
13161 local.sin_port = local_port;
13162 remote.sin_port = remote_port;
13163 memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
13164 memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
13165
13166 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13167 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13168 }
13169
13170 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)13171 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)
13172 {
13173 struct sockaddr_in6 local = {};
13174 struct sockaddr_in6 remote = {};
13175 local.sin6_family = remote.sin6_family = AF_INET6;
13176 local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
13177 local.sin6_port = local_port;
13178 remote.sin6_port = remote_port;
13179 memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
13180 memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
13181
13182 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13183 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13184 }
13185
13186 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)13187 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,
13188 u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13189 {
13190 return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
13191 return_policy_id, return_route_rule_id,
13192 return_skip_policy_id, return_pass_flags);
13193 }
13194
13195 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)13196 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
13197 necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
13198 {
13199 if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
13200 return EINVAL;
13201 }
13202
13203 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13204 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
13205 policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
13206 }
13207
13208 // Mark ID for Pass and IP Tunnel
13209 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13210 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13211 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
13212 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
13213 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13214 } else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
13215 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
13216 // This case is same as a PASS
13217 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13218 } else {
13219 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13220 }
13221 packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
13222 if (route_rule_id != 0) {
13223 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
13224 } else {
13225 packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13226 }
13227 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);
13228
13229 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13230 skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13231 // Only mark the skip policy if it is a valid policy ID
13232 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13233 } else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13234 inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13235 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13236 } else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
13237 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
13238 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
13239 // See necp_get_skip_policy_id_from_packet() and
13240 // necp_packet_should_skip_filters().
13241 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13242 } else {
13243 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13244 }
13245
13246 if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
13247 ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
13248 m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
13249 }
13250
13251 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13252 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
13253 packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
13254 }
13255
13256 return 0;
13257 }
13258
13259 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)13260 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
13261 {
13262 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13263 return EINVAL;
13264 }
13265
13266 // Mark ID for Pass and IP Tunnel
13267 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13268 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13269 } else {
13270 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13271 }
13272
13273 return 0;
13274 }
13275
13276 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)13277 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
13278 {
13279 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13280 return EINVAL;
13281 }
13282
13283 // Mark ID for Pass and IP Tunnel
13284 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13285 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13286 } else {
13287 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13288 }
13289
13290 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13291 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13292 } else {
13293 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13294 }
13295 return 0;
13296 }
13297
13298 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)13299 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
13300 {
13301 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13302 return EINVAL;
13303 }
13304
13305 // Mark ID for Pass and IP Tunnel
13306 if (interface != NULL) {
13307 packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
13308 }
13309
13310 return 0;
13311 }
13312
13313 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)13314 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
13315 {
13316 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13317 return EINVAL;
13318 }
13319
13320 if (is_keepalive) {
13321 packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
13322 } else {
13323 packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
13324 }
13325
13326 return 0;
13327 }
13328
13329 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)13330 necp_get_policy_id_from_packet(struct mbuf *packet)
13331 {
13332 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13333 return NECP_KERNEL_POLICY_ID_NONE;
13334 }
13335
13336 return packet->m_pkthdr.necp_mtag.necp_policy_id;
13337 }
13338
13339 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)13340 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
13341 {
13342 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13343 return NECP_KERNEL_POLICY_ID_NONE;
13344 }
13345
13346 // Check for overloaded value. See necp_mark_packet_from_socket().
13347 if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
13348 return NECP_KERNEL_POLICY_ID_NONE;
13349 }
13350
13351 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
13352 }
13353
13354 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)13355 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
13356 {
13357 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13358 return 0;
13359 }
13360
13361 return m_pftag(packet)->pftag_tag;
13362 }
13363
13364 bool
necp_packet_should_skip_filters(struct mbuf * packet)13365 necp_packet_should_skip_filters(struct mbuf *packet)
13366 {
13367 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13368 return false;
13369 }
13370
13371 // Check for overloaded value. See necp_mark_packet_from_socket().
13372 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
13373 }
13374
13375 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)13376 necp_get_last_interface_index_from_packet(struct mbuf *packet)
13377 {
13378 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13379 return 0;
13380 }
13381
13382 return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
13383 }
13384
13385 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)13386 necp_get_route_rule_id_from_packet(struct mbuf *packet)
13387 {
13388 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13389 return 0;
13390 }
13391
13392 return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
13393 }
13394
13395 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)13396 necp_get_app_uuid_from_packet(struct mbuf *packet,
13397 uuid_t app_uuid)
13398 {
13399 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13400 return EINVAL;
13401 }
13402
13403 bool found_mapping = FALSE;
13404 if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
13405 lck_rw_lock_shared(&necp_kernel_policy_lock);
13406 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);
13407 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
13408 if (entry != NULL) {
13409 uuid_copy(app_uuid, entry->uuid);
13410 found_mapping = true;
13411 }
13412 lck_rw_done(&necp_kernel_policy_lock);
13413 }
13414 if (!found_mapping) {
13415 uuid_clear(app_uuid);
13416 }
13417 return 0;
13418 }
13419
13420 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)13421 necp_get_is_keepalive_from_packet(struct mbuf *packet)
13422 {
13423 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13424 return FALSE;
13425 }
13426
13427 return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
13428 }
13429
13430 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)13431 necp_socket_get_content_filter_control_unit(struct socket *so)
13432 {
13433 struct inpcb *inp = sotoinpcb(so);
13434
13435 if (inp == NULL) {
13436 return 0;
13437 }
13438 return inp->inp_policyresult.results.filter_control_unit;
13439 }
13440
13441 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)13442 necp_socket_get_policy_gencount(struct socket *so)
13443 {
13444 struct inpcb *inp = so ? sotoinpcb(so) : NULL;
13445
13446 if (inp == NULL) {
13447 return 0;
13448 }
13449 return inp->inp_policyresult.policy_gencount;
13450 }
13451
13452 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)13453 necp_socket_should_use_flow_divert(struct inpcb *inp)
13454 {
13455 if (inp == NULL) {
13456 return FALSE;
13457 }
13458
13459 return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
13460 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13461 (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
13462 }
13463
13464 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)13465 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
13466 {
13467 if (inp == NULL) {
13468 return 0;
13469 }
13470
13471 if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13472 return 0;
13473 }
13474
13475 if (aggregate_unit != NULL &&
13476 inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13477 *aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13478 }
13479
13480 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13481 return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13482 }
13483
13484 return 0;
13485 }
13486
13487 bool
necp_socket_should_rescope(struct inpcb * inp)13488 necp_socket_should_rescope(struct inpcb *inp)
13489 {
13490 if (inp == NULL) {
13491 return FALSE;
13492 }
13493
13494 return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13495 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13496 }
13497
13498 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13499 necp_socket_get_rescope_if_index(struct inpcb *inp)
13500 {
13501 if (inp == NULL) {
13502 return 0;
13503 }
13504
13505 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13506 return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13507 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13508 return necp_get_primary_direct_interface_index();
13509 }
13510
13511 return 0;
13512 }
13513
13514 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13515 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13516 {
13517 if (inp == NULL) {
13518 return current_mtu;
13519 }
13520
13521 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13522 (inp->inp_flags & INP_BOUND_IF) &&
13523 inp->inp_boundifp) {
13524 u_int bound_interface_index = inp->inp_boundifp->if_index;
13525 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13526
13527 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13528 if (bound_interface_index != tunnel_interface_index) {
13529 ifnet_t tunnel_interface = NULL;
13530
13531 ifnet_head_lock_shared();
13532 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13533 ifnet_head_done();
13534
13535 if (tunnel_interface != NULL) {
13536 u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13537 u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13538 const char ipsec_prefix[] = "ipsec";
13539 if (delegate_tunnel_mtu != 0 &&
13540 strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13541 // For ipsec interfaces, calculate the overhead from the delegate interface
13542 u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13543 if (delegate_tunnel_mtu > tunnel_overhead) {
13544 delegate_tunnel_mtu -= tunnel_overhead;
13545 }
13546
13547 if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13548 // If the (delegate - overhead) < direct, return (delegate - overhead)
13549 return delegate_tunnel_mtu;
13550 } else {
13551 // Otherwise return direct
13552 return direct_tunnel_mtu;
13553 }
13554 } else {
13555 // For non-ipsec interfaces, just return the tunnel MTU
13556 return direct_tunnel_mtu;
13557 }
13558 }
13559 }
13560 }
13561
13562 // By default, just return the MTU passed in
13563 return current_mtu;
13564 }
13565
13566 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13567 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13568 {
13569 if (result_parameter == NULL) {
13570 return NULL;
13571 }
13572
13573 return ifindex2ifnet[result_parameter->tunnel_interface_index];
13574 }
13575
13576 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13577 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13578 {
13579 bool found_match = FALSE;
13580 bool can_rebind = FALSE;
13581 ifaddr_t ifa;
13582 union necp_sockaddr_union address_storage;
13583
13584 if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13585 return FALSE;
13586 }
13587
13588 // Match source address against interface addresses
13589 ifnet_lock_shared(interface);
13590 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13591 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13592 if (address_storage.sa.sa_family != family) {
13593 continue;
13594 }
13595
13596 if (family == AF_INET) {
13597 struct ip *ip = mtod(packet, struct ip *);
13598 if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13599 found_match = TRUE;
13600 break;
13601 }
13602 } else if (family == AF_INET6) {
13603 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13604 if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13605 found_match = TRUE;
13606 break;
13607 }
13608 }
13609 }
13610 }
13611 const uint32_t if_idx = interface->if_index;
13612 ifnet_lock_done(interface);
13613
13614 // If source address matched, attempt to construct a route to the destination address
13615 if (found_match) {
13616 ROUTE_RELEASE(new_route);
13617
13618 if (family == AF_INET) {
13619 struct ip *ip = mtod(packet, struct ip *);
13620 struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13621 dst4->sin_family = AF_INET;
13622 dst4->sin_len = sizeof(struct sockaddr_in);
13623 dst4->sin_addr = ip->ip_dst;
13624 rtalloc_scoped(new_route, if_idx);
13625 if (!ROUTE_UNUSABLE(new_route)) {
13626 can_rebind = TRUE;
13627 }
13628 } else if (family == AF_INET6) {
13629 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13630 struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13631 dst6->sin6_family = AF_INET6;
13632 dst6->sin6_len = sizeof(struct sockaddr_in6);
13633 dst6->sin6_addr = ip6->ip6_dst;
13634 rtalloc_scoped(new_route, if_idx);
13635 if (!ROUTE_UNUSABLE(new_route)) {
13636 can_rebind = TRUE;
13637 }
13638 }
13639 }
13640
13641 return can_rebind;
13642 }
13643
13644 static bool
necp_addr_is_loopback(struct sockaddr * address)13645 necp_addr_is_loopback(struct sockaddr *address)
13646 {
13647 if (address == NULL) {
13648 return FALSE;
13649 }
13650
13651 if (address->sa_family == AF_INET) {
13652 return IN_LOOPBACK(ntohl(SIN(address)->sin_addr.s_addr));
13653 } else if (address->sa_family == AF_INET6) {
13654 if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13655 return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13656 } else {
13657 // Match ::ffff:127.0.0.1 loopback address
13658 in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13659 return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13660 }
13661 }
13662
13663 return FALSE;
13664 }
13665
13666 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)13667 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13668 {
13669 // Note: This function only checks for the loopback addresses.
13670 // In the future, we may want to expand to also allow any traffic
13671 // going through the loopback interface, but until then, this
13672 // check is cheaper.
13673
13674 if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13675 return TRUE;
13676 }
13677
13678 if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13679 return TRUE;
13680 }
13681
13682 if (inp != NULL) {
13683 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13684 return TRUE;
13685 }
13686 if (inp->inp_vflag & INP_IPV4) {
13687 if (IN_LOOPBACK(ntohl(inp->inp_laddr.s_addr)) ||
13688 IN_LOOPBACK(ntohl(inp->inp_faddr.s_addr))) {
13689 return TRUE;
13690 }
13691 } else if (inp->inp_vflag & INP_IPV6) {
13692 if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13693 IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13694 return TRUE;
13695 }
13696 }
13697 } else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13698 return TRUE;
13699 }
13700
13701 if (packet != NULL) {
13702 struct ip *ip = mtod(packet, struct ip *);
13703 if (ip->ip_v == 4) {
13704 if (IN_LOOPBACK(ntohl(ip->ip_src.s_addr))) {
13705 return TRUE;
13706 }
13707 if (IN_LOOPBACK(ntohl(ip->ip_dst.s_addr))) {
13708 return TRUE;
13709 }
13710 } else if (ip->ip_v == 6) {
13711 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13712 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13713 return TRUE;
13714 }
13715 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13716 return TRUE;
13717 }
13718 }
13719 }
13720
13721 return FALSE;
13722 }
13723
13724 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13725 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13726 {
13727 if (inp != NULL) {
13728 if (!(inp->inp_vflag & INP_IPV6)) {
13729 return false;
13730 }
13731 if (INP_INTCOPROC_ALLOWED(inp)) {
13732 return true;
13733 }
13734 if ((inp->inp_flags & INP_BOUND_IF) &&
13735 IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13736 return true;
13737 }
13738 return false;
13739 }
13740 if (packet != NULL) {
13741 struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13742 struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13743 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13744 NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13745 return true;
13746 }
13747 }
13748
13749 return false;
13750 }
13751
13752 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13753 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13754 {
13755 char dest_str[MAX_IPv6_STR_LEN];
13756
13757 if (necp_drop_dest_debug > 0) {
13758 if (sau->sa.sa_family == AF_INET) {
13759 (void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13760 } else if (sau->sa.sa_family == AF_INET6) {
13761 (void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13762 } else {
13763 dest_str[0] = 0;
13764 }
13765 }
13766 for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13767 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13768 struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13769
13770 if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13771 if (necp_drop_dest_debug > 0) {
13772 char subnet_str[MAX_IPv6_STR_LEN];
13773 struct proc *p = current_proc();
13774 pid_t pid = proc_pid(p);
13775
13776 if (sau->sa.sa_family == AF_INET) {
13777 (void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13778 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);
13779 } else if (sau->sa.sa_family == AF_INET6) {
13780 (void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13781 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);
13782 }
13783 }
13784 return true;
13785 }
13786 }
13787 if (necp_drop_dest_debug > 1) {
13788 struct proc *p = current_proc();
13789 pid_t pid = proc_pid(p);
13790
13791 os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13792 }
13793 return false;
13794 }
13795
13796 static int
13797 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13798 {
13799 #pragma unused(arg1, arg2, oidp)
13800 int changed = 0;
13801 int error = 0;
13802 struct necp_drop_dest_policy tmp_drop_dest_policy;
13803 struct proc *p = current_proc();
13804 pid_t pid = proc_pid(p);
13805
13806 if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13807 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13808 NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13809 return EPERM;
13810 }
13811 if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13812 NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13813 return EINVAL;
13814 }
13815
13816 memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13817 error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13818 if (error != 0) {
13819 NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13820 return error;
13821 }
13822 if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13823 return error;
13824 }
13825
13826 //
13827 // Validate the passed parameters
13828 //
13829 if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13830 NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13831 return EINVAL;
13832 }
13833 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13834 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13835 struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13836
13837 switch (tmp_drop_dest_entry->level) {
13838 case NECP_SESSION_PRIORITY_UNKNOWN:
13839 if (tmp_drop_dest_policy.entry_count != 0) {
13840 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);
13841 return EINVAL;
13842 }
13843 break;
13844 case NECP_SESSION_PRIORITY_CONTROL:
13845 case NECP_SESSION_PRIORITY_CONTROL_1:
13846 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13847 case NECP_SESSION_PRIORITY_HIGH:
13848 case NECP_SESSION_PRIORITY_HIGH_1:
13849 case NECP_SESSION_PRIORITY_HIGH_2:
13850 case NECP_SESSION_PRIORITY_HIGH_3:
13851 case NECP_SESSION_PRIORITY_HIGH_4:
13852 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13853 case NECP_SESSION_PRIORITY_DEFAULT:
13854 case NECP_SESSION_PRIORITY_LOW:
13855 if (tmp_drop_dest_policy.entry_count == 0) {
13856 NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13857 return EINVAL;
13858 }
13859 break;
13860 default: {
13861 NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13862 return EINVAL;
13863 }
13864 }
13865
13866 switch (npca->address.sa.sa_family) {
13867 case AF_INET: {
13868 if (npca->prefix > 32) {
13869 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13870 return EINVAL;
13871 }
13872 if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
13873 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
13874 return EINVAL;
13875 }
13876 if (npca->address.sin.sin_port != 0) {
13877 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);
13878 return EINVAL;
13879 }
13880 break;
13881 }
13882 case AF_INET6: {
13883 if (npca->prefix > 128) {
13884 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13885 return EINVAL;
13886 }
13887 if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
13888 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
13889 return EINVAL;
13890 }
13891 if (npca->address.sin6.sin6_port != 0) {
13892 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);
13893 return EINVAL;
13894 }
13895 if (npca->address.sin6.sin6_flowinfo != 0) {
13896 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);
13897 return EINVAL;
13898 }
13899 if (npca->address.sin6.sin6_scope_id != 0) {
13900 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);
13901 return EINVAL;
13902 }
13903 break;
13904 }
13905 default: {
13906 return EINVAL;
13907 }
13908 }
13909 }
13910
13911 //
13912 // Commit the changed policy
13913 //
13914 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
13915 memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
13916
13917 necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
13918 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13919 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13920 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13921
13922 memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
13923
13924 necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
13925 }
13926 lck_rw_done(&necp_kernel_policy_lock);
13927
13928 return 0;
13929 }
13930
13931 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])13932 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
13933 {
13934 uint16_t fam = address->sa.sa_family;
13935 memset(addr_str, 0, MAX_IPv6_STR_LEN);
13936 if (fam == AF_INET) {
13937 (void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
13938 } else if (fam == AF_INET6) {
13939 (void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
13940 }
13941 return __unsafe_null_terminated_from_indexable(addr_str);
13942 }
13943