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_domain_filter {
287 LIST_ENTRY(necp_domain_filter) owner_chain;
288 LIST_ENTRY(necp_domain_filter) chain;
289 u_int32_t id;
290 struct net_bloom_filter *filter;
291 os_refcnt_t refcount;
292 };
293 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
294
295 /*
296 * Filter id space is split between domain bloom filter id and domain trie filter id.
297 * id <= 10000 - bloom filter ids
298 * id > 10000 - trie filter ids
299 */
300 #define NECP_DOMAIN_FILTER_ID_MAX 10000
301 #define NECP_DOMAIN_TRIE_ID_START NECP_DOMAIN_FILTER_ID_MAX
302 #define NECP_IS_DOMAIN_FILTER_ID(id) (id <= NECP_DOMAIN_FILTER_ID_MAX)
303
304 struct necp_domain_trie {
305 LIST_ENTRY(necp_domain_trie) owner_chain;
306 LIST_ENTRY(necp_domain_trie) chain;
307 u_int32_t id;
308 struct necp_domain_trie_request *trie_request;
309 size_t trie_request_size;
310 struct net_trie trie;
311 os_refcnt_t refcount;
312 };
313 static LIST_HEAD(necp_domain_trie_list, necp_domain_trie) necp_global_domain_trie_list;
314
315 struct necp_session {
316 u_int8_t necp_fd_type;
317 u_int32_t control_unit;
318 u_int32_t session_priority; // Descriptive priority rating
319 u_int32_t session_order;
320
321 necp_policy_id last_policy_id;
322
323 decl_lck_mtx_data(, lock);
324
325 bool proc_locked; // Messages must come from proc_uuid
326 uuid_t proc_uuid;
327 int proc_pid;
328
329 bool dirty;
330 LIST_HEAD(_policies, necp_session_policy) policies;
331
332 struct necp_domain_filter_list domain_filters;
333 struct necp_domain_trie_list domain_tries;
334
335 TAILQ_ENTRY(necp_session) chain;
336 };
337
338 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
339 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
340
341 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
342
343 struct necp_socket_info {
344 pid_t pid;
345 int32_t pid_version;
346 uid_t uid;
347 uid_t real_uid;
348 union necp_sockaddr_union local_addr;
349 union necp_sockaddr_union remote_addr;
350 u_int32_t bound_interface_index;
351 u_int32_t bound_interface_flags;
352 u_int32_t bound_interface_eflags;
353 u_int32_t bound_interface_xflags;
354 u_int32_t traffic_class;
355 u_int16_t protocol;
356 u_int16_t scheme_port;
357 u_int32_t application_id;
358 u_int32_t real_application_id;
359 u_int32_t account_id;
360 u_int32_t drop_order;
361 u_int32_t client_flags;
362 char *domain __null_terminated;
363 char *url __null_terminated;
364 struct soflow_hash_entry *soflow_entry;
365 unsigned is_entitled : 1;
366 unsigned has_client : 1;
367 unsigned has_system_signed_result : 1;
368 unsigned is_platform_binary : 1;
369 unsigned used_responsible_pid : 1;
370 unsigned is_loopback : 1;
371 unsigned real_is_platform_binary : 1;
372 unsigned is_delegated : 1;
373 unsigned is_local : 1;
374 unsigned __pad_bits : 7;
375 };
376
377 static LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
378 static LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
379 static LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
380 &necp_kernel_policy_mtx_attr);
381
382 static LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
383 static LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
384
385 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
386
387 /*
388 * On modification, invalidate cached lookups by bumping the generation count.
389 * Other calls will need to take the slowpath of taking
390 * the subsystem lock.
391 */
392 static volatile int32_t necp_kernel_socket_policies_gencount;
393 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
394 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
395 necp_kernel_socket_policies_gencount = 1; \
396 } \
397 } while (0)
398
399 /*
400 * Drop-all Bypass:
401 * Allow priviledged processes to bypass the default drop-all
402 * via entitlement check. For OSX, since entitlement check is
403 * not supported for configd, configd signing identity is checked
404 * instead.
405 */
406 #define SIGNING_ID_CONFIGD "com.apple.configd"
407 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
408
409 typedef enum {
410 NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
411 NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
412 NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
413 } necp_drop_all_bypass_check_result_t;
414
415 static u_int64_t necp_kernel_application_policies_condition_mask;
416 static size_t necp_kernel_application_policies_count;
417 static u_int64_t necp_kernel_socket_policies_condition_mask;
418 static size_t necp_kernel_socket_policies_count;
419 static size_t necp_kernel_socket_policies_non_app_count;
420 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
421 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
422 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
423 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
424 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
425 static size_t necp_kernel_socket_policies_app_layer_map_count;
426 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_app_layer_map;
427 /*
428 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
429 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
430 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
431 *
432 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
433 */
434
435 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
436 static size_t necp_kernel_ip_output_policies_count;
437 static size_t necp_kernel_ip_output_policies_non_id_count;
438 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
439 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
440 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
441 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
442 static struct necp_kernel_ip_output_policy ** __indexable necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
443 static struct necp_kernel_socket_policy pass_policy =
444 {
445 .id = NECP_KERNEL_POLICY_ID_NO_MATCH,
446 .result = NECP_KERNEL_POLICY_RESULT_PASS,
447 };
448
449 static struct necp_session *necp_create_session(void);
450 static void necp_delete_session(struct necp_session *session);
451
452 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
453 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
454 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
455
456 #define MAX_RESULT_STRING_LEN 64
457 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);
458
459 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);
460 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
461 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
462 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
463 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
464 static void necp_policy_apply_all(struct necp_session *session);
465
466 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);
467 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
468 static bool necp_kernel_socket_policies_reprocess(void);
469 static bool necp_kernel_socket_policies_update_uuid_table(void);
470 static inline struct necp_kernel_socket_policy * necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
471 struct necp_socket_info *info,
472 necp_kernel_policy_filter *return_filter,
473 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
474 size_t *return_route_rule_id_array_count,
475 size_t route_rule_id_array_count,
476 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
477 size_t netagent_array_count,
478 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
479 size_t netagent_use_flags_array_count,
480 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
481 u_int32_t num_required_agent_types,
482 proc_t proc,
483 u_int16_t pf_tag,
484 necp_kernel_policy_id *skip_policy_id,
485 struct rtentry *rt,
486 necp_kernel_policy_result *return_drop_dest_policy_result,
487 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
488 u_int32_t *return_flow_divert_aggregate_unit,
489 struct socket *so,
490 int debug);
491 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);
492 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
493 static bool necp_kernel_ip_output_policies_reprocess(void);
494
495 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
496 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);
497 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
498 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
499 static bool necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits);
500 static bool necp_addr_is_empty(struct sockaddr *addr);
501 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);
502 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
503
504 struct necp_uuid_id_mapping {
505 LIST_ENTRY(necp_uuid_id_mapping) chain;
506 uuid_t uuid;
507 u_int32_t id;
508 os_refcnt_t refcount;
509 u_int32_t table_usecount; // Add to UUID policy table count
510 };
511 static size_t necp_num_uuid_app_id_mappings;
512 static bool necp_uuid_app_id_mappings_dirty;
513 #define NECP_UUID_APP_ID_HASH_SIZE 64
514 static u_long necp_uuid_app_id_hash_mask;
515 static u_long necp_uuid_app_id_hash_num_buckets;
516 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_agent_uuid_id_list; // App map is real hash table, agent map is just mapping
517 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
518 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
519 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
520 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t agent_id);
521
522 static bool necp_agent_id_is_uuid(u_int32_t agent_id);
523 static struct necp_uuid_id_mapping *necp_uuid_lookup_agent_id_with_uuid_locked(uuid_t uuid);
524 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_agent_id_locked(u_int32_t agent_id);
525 static u_int32_t necp_create_agent_uuid_id_mapping(uuid_t uuid);
526 static bool necp_remove_agent_uuid_id_mapping(uuid_t uuid);
527 static bool necp_remove_agent_uuid_id_mapping_with_agent_id(u_int32_t agent_id);
528
529 struct necp_agent_type_id_mapping {
530 LIST_ENTRY(necp_agent_type_id_mapping) chain;
531 struct necp_policy_condition_agent_type agent_type;
532 u_int32_t id;
533 os_refcnt_t refcount;
534 };
535 static LIST_HEAD(necp_agent_type_id_mapping_list, necp_agent_type_id_mapping) necp_agent_type_id_list;
536 static u_int32_t necp_create_agent_type_to_id_mapping(struct necp_policy_condition_agent_type *agent_type);
537 static bool necp_remove_agent_type_to_id_mapping(u_int32_t agent_type_id);
538 static struct necp_agent_type_id_mapping *necp_lookup_agent_type_with_id_locked(u_int32_t agent_id);
539
540 struct necp_string_id_mapping {
541 LIST_ENTRY(necp_string_id_mapping) chain;
542 char *string __null_terminated;
543 necp_app_id id;
544 os_refcnt_t refcount;
545 };
546 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
547 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
548 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
549 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
550
551 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);
552 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
553 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
554
555 static u_int32_t necp_create_domain_trie(struct necp_domain_trie_list *list, struct necp_domain_trie_list *owner_list,
556 struct necp_domain_trie_request *necp_trie_request, size_t necp_trie_request_size);
557 static bool necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id);
558 static void necp_free_domain_trie(struct necp_domain_trie *trie);
559 static struct necp_domain_trie *necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id);
560 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);
561
562 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
563 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
564
565 static char * __null_terminated necp_create_trimmed_domain(char * __sized_by(length)string, size_t length);
566 static inline int necp_count_dots(char * __sized_by(length)string, size_t length);
567
568 static char * __null_terminated necp_copy_string(char * __sized_by(length)string, size_t length);
569 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);
570
571 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
572
573 #define MAX_ROUTE_RULE_INTERFACES 10
574 struct necp_route_rule {
575 LIST_ENTRY(necp_route_rule) chain;
576 u_int32_t id;
577 u_int32_t netagent_id;
578 u_int32_t control_unit;
579 u_int32_t match_netagent_id;
580 u_int32_t effective_type;
581 u_int8_t default_action;
582 u_int8_t cellular_action;
583 u_int8_t wifi_action;
584 u_int8_t wired_action;
585 u_int8_t expensive_action;
586 u_int8_t constrained_action;
587 u_int8_t companion_action;
588 u_int8_t vpn_action;
589 u_int8_t ultra_constrained_action;
590 u_int exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
591 u_int8_t exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
592 os_refcnt_t refcount;
593 };
594 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
595 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);
596 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
597 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
598 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,
599 u_int32_t route_rule_id, u_int32_t *interface_type_denied, bool *ultra_constrained_denied);
600 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);
601 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
602 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);
603 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
604 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
605
606 #define MAX_AGGREGATE_ROUTE_RULES 16
607 struct necp_aggregate_route_rule {
608 LIST_ENTRY(necp_aggregate_route_rule) chain;
609 u_int32_t id;
610 u_int32_t rule_ids[MAX_AGGREGATE_ROUTE_RULES];
611 };
612 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
613 static u_int32_t necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids);
614
615 // Sysctl definitions
616 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
617 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
618 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
619
620 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
621 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
622 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
623 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
624 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
625 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
626 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
627 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", "");
628 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", "");
629 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", "");
630 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
631 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, "");
632 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
633 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
634 SYSCTL_INT(_net_necp, NECPCTL_TRIE_COUNT, trie_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_trie_count, 0, "");
635
636 static struct necp_drop_dest_policy necp_drop_dest_policy;
637 static int necp_drop_dest_debug = 0; // 0: off, 1: match, >1: every evaluation
638 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
639
640 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
641 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
642 0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
643
644 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
645
646 /*
647 * data tracing control -
648 *
649 * necp_data_tracing_level : 1 for brief trace, 2 for policy details, 3 for condition details
650 * necp_data_tracing_port : match traffic with specified port
651 * necp_data_tracing_proto : match traffic with specified protocol
652 * necp_data_tracing_pid : match traffic with specified pid (only applied at socket level)
653 * necp_data_tracing_ifindex : match traffic on specified ifindex
654 * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched. Default is 0 to trace traffic if any specified attributes matched.
655 * data_tracing_session_order : match policies in the specified session - log traffic that hit these policies
656 * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
657 */
658 static int necp_data_tracing_level = 0;
659 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
660
661 static int necp_data_tracing_port = 0;
662 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
663
664 static int necp_data_tracing_proto = 0;
665 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
666
667 static int necp_data_tracing_pid = 0;
668 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
669
670 static int necp_data_tracing_ifindex = 0;
671 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
672
673 static int necp_data_tracing_match_all = 0;
674 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
675
676 static int necp_data_tracing_session_order = 0;
677 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
678
679 static int necp_data_tracing_policy_order = 0;
680 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
681
682 #define NECP_DATA_TRACE_LEVEL_BRIEF 1
683 #define NECP_DATA_TRACE_LEVEL_POLICY 2
684 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
685 #define NECP_DATA_TRACE_LEVEL_DP 4
686
687 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
688 (pid == necp_data_tracing_pid)
689 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
690 (protocol == necp_data_tracing_proto)
691 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
692 (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
693 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
694 (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
695 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
696 (ifindex == necp_data_tracing_ifindex)
697
698 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
699 ((necp_data_tracing_level && \
700 ((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
701 (necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
702 (necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
703 (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)
704
705 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
706 ((necp_data_tracing_level && \
707 ((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
708 (!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
709 (!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
710 (!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)
711
712 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
713 (necp_data_tracing_match_all ? \
714 NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
715 NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
716
717 #define NECP_DATA_TRACE_ON(debug) (debug)
718 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
719 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
720 #define NECP_DATA_TRACE_DP_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_CONDITION)
721
722 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
723
724 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
725 if (NECP_DATA_TRACE_ON(debug)) { \
726 char laddr_str[MAX_IPv6_STR_LEN]; \
727 char raddr_str[MAX_IPv6_STR_LEN]; \
728 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>", \
729 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); \
730 }
731
732 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
733 if (NECP_DATA_TRACE_ON(debug)) { \
734 char laddr_str[MAX_IPv6_STR_LEN]; \
735 char raddr_str[MAX_IPv6_STR_LEN]; \
736 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>", \
737 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); \
738 }
739
740 #define NECP_DATA_TRACE_LOG_SOCKET_DP(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
741 if (NECP_DATA_TRACE_ON(debug)) { \
742 char laddr_str[MAX_IPv6_STR_LEN]; \
743 char raddr_str[MAX_IPv6_STR_LEN]; \
744 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>", \
745 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); \
746 }
747
748 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
749 if (NECP_DATA_TRACE_ON(debug)) { \
750 char laddr_str[MAX_IPv6_STR_LEN]; \
751 char raddr_str[MAX_IPv6_STR_LEN]; \
752 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)", \
753 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]); \
754 }
755
756 #define NECP_DATA_TRACE_LOG_SOCKET_BRIEF(debug, socket, caller, log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id) \
757 if (NECP_DATA_TRACE_ON(debug)) { \
758 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - <policy_id %d skip_policy_id %d> <cached policy_id %d skip_policy_id %d>", \
759 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id); \
760 }
761
762 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
763 if (NECP_DATA_TRACE_ON(debug)) { \
764 char laddr_str[MAX_IPv6_STR_LEN]; \
765 char raddr_str[MAX_IPv6_STR_LEN]; \
766 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>", \
767 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)); \
768 }
769
770 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
771 if (NECP_DATA_TRACE_ON(debug)) { \
772 char laddr_str[MAX_IPv6_STR_LEN]; \
773 char raddr_str[MAX_IPv6_STR_LEN]; \
774 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>", \
775 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); \
776 }
777
778 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
779 if (NECP_DATA_TRACE_ON(debug)) { \
780 char laddr_str[MAX_IPv6_STR_LEN]; \
781 char raddr_str[MAX_IPv6_STR_LEN]; \
782 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)", \
783 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]); \
784 }
785
786 #define NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, socket, caller, log_msg) \
787 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
788 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)", \
789 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); \
790 }
791
792 #define NECP_DATA_TRACE_LOG_POLICY_IP(debug, caller, log_msg) \
793 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
794 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)", \
795 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); \
796 }
797
798 #define NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
799 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
800 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)>", \
801 caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
802 }
803
804 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
805 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
806 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
807 caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
808 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
809 }
810
811 #define NECP_DATA_TRACE_LOG_CONDITION_IP(debug, caller, negate, name, val, input) \
812 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
813
814 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR(debug, caller, negate, name, val, input) \
815 NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
816
817
818 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
819 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
820 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)>", \
821 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
822 }
823
824 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
825 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
826 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
827 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
828 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
829 }
830
831 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, caller, negate, name, val, input) \
832 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val, 0, 0, input, 0, 0)
833
834 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, caller, negate, name, val, input) \
835 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
836
837 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
838 (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
839 addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
840
841 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
842 "INVALID",
843 "PASS",
844 "SKIP",
845 "DROP",
846 "SOCKET_DIVERT",
847 "SOCKET_FILTER",
848 "IP_TUNNEL",
849 "IP_FILTER",
850 "TRIGGER",
851 "TRIGGER_IF_NEEDED",
852 "TRIGGER_SCOPED",
853 "NO_TRIGGER_SCOPED",
854 "SOCKET_SCOPED",
855 "ROUTE_RULES",
856 "USE_NETAGENT",
857 "NETAGENT_SCOPED",
858 "SCOPED_DIRECT",
859 "ALLOW_UNENTITLED",
860 "REMOVE_NETAGENT",
861 "REMOVE_NETAGENT_TYPE"
862 };
863
864
865 #define NECP_DDE_ENTITLEMENT "com.apple.developer.media-device-discovery-extension"
866
867 static int necp_drop_loopback_count = 0;
868 SYSCTL_INT(_net_necp, OID_AUTO, drop_loopback_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_drop_loopback_count, 0, "");
869
870 static bool
necp_address_is_local_interface_address(union necp_sockaddr_union * addr)871 necp_address_is_local_interface_address(union necp_sockaddr_union *addr)
872 {
873 bool is_interface_address = false;
874 if (addr == NULL) {
875 return false;
876 }
877
878 // Clean up the address before comparison with interface addresses
879 // Transform remote_addr into the ifaddr form
880 // IPv6 Scope IDs are always embedded in the ifaddr list
881 struct sockaddr_storage remote_address_sanitized;
882 u_int ifscope = IFSCOPE_NONE;
883 (void)sa_copy(SA(addr), &remote_address_sanitized, &ifscope);
884 SIN(&remote_address_sanitized)->sin_port = 0;
885 if (remote_address_sanitized.ss_family == AF_INET6) {
886 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
887 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
888 }
889 }
890
891 // Check if remote address is an interface address
892 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
893 if (ifa != NULL && ifa->ifa_ifp != NULL) {
894 is_interface_address = true;
895 }
896 if (ifa != NULL) {
897 ifaddr_release(ifa);
898 ifa = NULL;
899 }
900
901 return is_interface_address;
902 }
903
904 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, addr, include_local_addresses) \
905 ((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)))
906
907 // Session order allocation
908 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)909 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
910 {
911 u_int32_t new_order = 0;
912
913 // For now, just allocate 1000 orders for each priority
914 if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
915 priority = NECP_SESSION_PRIORITY_DEFAULT;
916 }
917
918 // Use the control unit to decide the offset into the priority list
919 new_order = (control_unit) + ((priority - 1) * 1000);
920
921 return new_order;
922 }
923
924 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)925 necp_get_first_order_for_priority(u_int32_t priority)
926 {
927 if (priority == 0) {
928 return 0;
929 }
930 return ((priority - 1) * 1000) + 1;
931 }
932
933 // Sysctl handler
934 static int
935 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
936 {
937 #pragma unused(arg1, arg2)
938 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
939 necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
940 return error;
941 }
942
943 static int
944 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
945 {
946 #pragma unused(arg1, arg2)
947 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
948 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
949 return error;
950 }
951
952 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
953 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)954 _necp_process_drop_order_inner(kauth_cred_t cred)
955 {
956 if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
957 priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
958 return necp_drop_unentitled_order;
959 } else {
960 return 0;
961 }
962 }
963
964 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
965 #pragma GCC poison _necp_process_drop_order_inner
966
967 static int
968 sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS
969 {
970 #pragma unused(arg1, arg2)
971 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
972 necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
973 return error;
974 }
975
976 static inline bool
necp_socket_is_connected(struct inpcb * inp)977 necp_socket_is_connected(struct inpcb *inp)
978 {
979 return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
980 }
981
982
983 // Session fd
984
985 static int necp_session_op_close(struct fileglob *, vfs_context_t);
986
987 static const struct fileops necp_session_fd_ops = {
988 .fo_type = DTYPE_NETPOLICY,
989 .fo_read = fo_no_read,
990 .fo_write = fo_no_write,
991 .fo_ioctl = fo_no_ioctl,
992 .fo_select = fo_no_select,
993 .fo_close = necp_session_op_close,
994 .fo_drain = fo_no_drain,
995 .fo_kqfilter = fo_no_kqfilter,
996 };
997
998 static inline int
necp_is_platform_binary(proc_t proc)999 necp_is_platform_binary(proc_t proc)
1000 {
1001 return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
1002 }
1003
1004 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)1005 necp_check_drop_all_bypass_result(proc_t proc)
1006 {
1007 if (proc == NULL) {
1008 proc = current_proc();
1009 if (proc == NULL) {
1010 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1011 }
1012 }
1013
1014 #if defined(XNU_TARGET_OS_OSX)
1015 const char *signing_id __null_terminated = NULL;
1016 const bool isConfigd = (necp_is_platform_binary(proc) &&
1017 (signing_id = cs_identity_get(proc)) &&
1018 (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
1019 (strcmp(signing_id, SIGNING_ID_CONFIGD) == 0));
1020 if (isConfigd) {
1021 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1022 }
1023 #endif
1024
1025 const task_t __single task = proc_task(proc);
1026 if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
1027 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1028 } else {
1029 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1030 }
1031 }
1032
1033 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)1034 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
1035 {
1036 #pragma unused(uap)
1037 int error = 0;
1038 struct necp_session *session = NULL;
1039 struct fileproc * __single fp = NULL;
1040 int fd = -1;
1041 uid_t uid = kauth_cred_getuid(kauth_cred_get());
1042
1043 if (!necp_is_platform_binary(p)) {
1044 NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
1045 error = EACCES;
1046 goto done;
1047 }
1048
1049 if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
1050 NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
1051 error = EACCES;
1052 goto done;
1053 }
1054
1055 error = falloc(p, &fp, &fd);
1056 if (error != 0) {
1057 goto done;
1058 }
1059
1060 session = necp_create_session();
1061 if (session == NULL) {
1062 error = ENOMEM;
1063 goto done;
1064 }
1065
1066 fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
1067 fp->fp_glob->fg_flag = 0;
1068 fp->fp_glob->fg_ops = &necp_session_fd_ops;
1069 fp_set_data(fp, session);
1070
1071 proc_fdlock(p);
1072 procfdtbl_releasefd(p, fd, NULL);
1073 fp_drop(p, fd, fp, 1);
1074 proc_fdunlock(p);
1075
1076 *retval = fd;
1077 done:
1078 if (error != 0) {
1079 if (fp != NULL) {
1080 fp_free(p, fd, fp);
1081 fp = NULL;
1082 }
1083 }
1084
1085 return error;
1086 }
1087
1088 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)1089 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
1090 {
1091 #pragma unused(ctx)
1092 struct necp_session *session = (struct necp_session *)fg_get_data(fg);
1093 fg_set_data(fg, NULL);
1094
1095 if (session != NULL) {
1096 necp_policy_mark_all_for_deletion(session);
1097 necp_policy_apply_all(session);
1098 necp_delete_session(session);
1099 return 0;
1100 } else {
1101 return ENOENT;
1102 }
1103 }
1104
1105 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)1106 necp_session_find_from_fd(struct proc *p, int fd,
1107 struct fileproc **fpp, struct necp_session **session)
1108 {
1109 struct fileproc * __single fp = NULL;
1110 int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
1111
1112 if (error == 0) {
1113 *fpp = fp;
1114 *session = (struct necp_session *)fp_get_data(fp);
1115 if ((*session)->necp_fd_type != necp_fd_type_session) {
1116 // Not a client fd, ignore
1117 fp_drop(p, fd, fp, 0);
1118 error = EINVAL;
1119 }
1120 }
1121
1122 return error;
1123 }
1124
1125 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1126 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1127 {
1128 int error = 0;
1129 u_int8_t * __indexable tlv_buffer = NULL;
1130
1131 if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
1132 NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1133 error = EINVAL;
1134 goto done;
1135 }
1136
1137 if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
1138 NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1139 error = EINVAL;
1140 goto done;
1141 }
1142
1143 if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
1144 error = ENOMEM;
1145 goto done;
1146 }
1147
1148 error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
1149 if (error != 0) {
1150 NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1151 goto done;
1152 }
1153
1154 necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1155 if (error != 0) {
1156 NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1157 goto done;
1158 }
1159
1160 error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1161 if (error != 0) {
1162 NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1163 goto done;
1164 }
1165
1166 done:
1167 if (tlv_buffer != NULL) {
1168 kfree_data(tlv_buffer, uap->in_buffer_length);
1169 tlv_buffer = NULL;
1170 }
1171 *retval = error;
1172
1173 return error;
1174 }
1175
1176 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1177 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1178 {
1179 int error = 0;
1180 u_int8_t * __indexable response = NULL;
1181
1182 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1183 NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1184 error = EINVAL;
1185 goto done;
1186 }
1187
1188 necp_policy_id policy_id = 0;
1189 error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1190 if (error != 0) {
1191 NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1192 goto done;
1193 }
1194
1195 struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1196 if (policy == NULL || policy->pending_deletion) {
1197 NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1198 error = ENOENT;
1199 goto done;
1200 }
1201
1202 u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1203 u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1204 u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1205
1206 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1207 NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1208 error = EINVAL;
1209 goto done;
1210 }
1211
1212 if (response_size > NECP_MAX_POLICY_SIZE) {
1213 NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1214 error = EINVAL;
1215 goto done;
1216 }
1217
1218 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1219 if (response == NULL) {
1220 error = ENOMEM;
1221 goto done;
1222 }
1223
1224 u_int8_t *cursor = response;
1225 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1226 if (result_tlv_size) {
1227 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, (void *)&policy->result, response, response_size);
1228 }
1229 if (policy->conditions_size) {
1230 memcpy(response + (cursor - response), policy->conditions, policy->conditions_size);
1231 }
1232
1233 error = copyout(response, uap->out_buffer, response_size);
1234 if (error != 0) {
1235 NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1236 goto done;
1237 }
1238
1239 done:
1240 if (response != NULL) {
1241 kfree_data(response, response_size);
1242 response = NULL;
1243 }
1244 *retval = error;
1245
1246 return error;
1247 }
1248
1249 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1250 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1251 {
1252 int error = 0;
1253
1254 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1255 NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1256 error = EINVAL;
1257 goto done;
1258 }
1259
1260 necp_policy_id delete_policy_id = 0;
1261 error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1262 if (error != 0) {
1263 NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1264 goto done;
1265 }
1266
1267 struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1268 if (policy == NULL || policy->pending_deletion) {
1269 NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1270 error = ENOENT;
1271 goto done;
1272 }
1273
1274 necp_policy_mark_for_deletion(session, policy);
1275 done:
1276 *retval = error;
1277 return error;
1278 }
1279
1280 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1281 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1282 {
1283 #pragma unused(uap)
1284 necp_policy_apply_all(session);
1285 *retval = 0;
1286 return 0;
1287 }
1288
1289 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1290 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1291 {
1292 u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1293 u_int32_t response_size = 0;
1294 u_int8_t * __indexable response = NULL;
1295 int num_policies = 0;
1296 int cur_policy_index = 0;
1297 int error = 0;
1298 struct necp_session_policy *policy;
1299
1300 LIST_FOREACH(policy, &session->policies, chain) {
1301 if (!policy->pending_deletion) {
1302 num_policies++;
1303 }
1304 }
1305
1306 if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1307 NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1308 error = EINVAL;
1309 goto done;
1310 }
1311
1312 response_size = num_policies * tlv_size;
1313 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1314 NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1315 error = EINVAL;
1316 goto done;
1317 }
1318
1319 // Create a response with one Policy ID TLV for each policy
1320 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1321 if (response == NULL) {
1322 error = ENOMEM;
1323 goto done;
1324 }
1325
1326 u_int8_t *cursor = response;
1327 LIST_FOREACH(policy, &session->policies, chain) {
1328 if (!policy->pending_deletion && cur_policy_index < num_policies) {
1329 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1330 cur_policy_index++;
1331 }
1332 }
1333
1334 error = copyout(response, uap->out_buffer, response_size);
1335 if (error != 0) {
1336 NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1337 goto done;
1338 }
1339
1340 done:
1341 if (response != NULL) {
1342 kfree_data(response, response_size);
1343 response = NULL;
1344 }
1345 *retval = error;
1346
1347 return error;
1348 }
1349
1350
1351 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1352 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1353 {
1354 #pragma unused(uap)
1355 necp_policy_mark_all_for_deletion(session);
1356 *retval = 0;
1357 return 0;
1358 }
1359
1360 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1361 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1362 {
1363 int error = 0;
1364 struct necp_session_policy *policy = NULL;
1365 struct necp_session_policy *temp_policy = NULL;
1366
1367 if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1368 NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1369 error = EINVAL;
1370 goto done;
1371 }
1372
1373 necp_session_priority requested_session_priority = 0;
1374 error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1375 if (error != 0) {
1376 NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1377 goto done;
1378 }
1379
1380 // Enforce special session priorities with entitlements
1381 if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1382 requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1383 requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1384 requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1385 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1386 if (cred_result != 0) {
1387 NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1388 error = EPERM;
1389 goto done;
1390 }
1391 }
1392
1393 if (session->session_priority != requested_session_priority) {
1394 session->session_priority = requested_session_priority;
1395 session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1396 session->dirty = TRUE;
1397
1398 // Mark all policies as needing updates
1399 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1400 policy->pending_update = TRUE;
1401 }
1402 }
1403
1404 done:
1405 *retval = error;
1406 return error;
1407 }
1408
1409 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1410 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1411 {
1412 #pragma unused(uap)
1413 session->proc_locked = TRUE;
1414 *retval = 0;
1415 return 0;
1416 }
1417
1418 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1419 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1420 {
1421 #pragma unused(session)
1422 int error = 0;
1423
1424 if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1425 NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1426 error = EINVAL;
1427 goto done;
1428 }
1429
1430 error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1431 done:
1432 *retval = error;
1433 return error;
1434 }
1435
1436 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1437 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1438 {
1439 int error = 0;
1440 struct net_bloom_filter *bloom_filter = NULL;
1441 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1442 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1443
1444 if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1445 in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1446 uap->in_buffer == 0) {
1447 NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1448 error = EINVAL;
1449 goto done;
1450 }
1451
1452 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1453 NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1454 error = EINVAL;
1455 goto done;
1456 }
1457
1458 bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1459 if (bloom_filter == NULL) {
1460 NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1461 error = ENOMEM;
1462 goto done;
1463 }
1464
1465 error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1466 if (error != 0) {
1467 NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1468 goto done;
1469 }
1470
1471 size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1472 if (expected_filter_size != in_buffer_length) {
1473 NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1474 error = EINVAL;
1475 goto done;
1476 }
1477
1478 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1479 u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1480 lck_rw_done(&necp_kernel_policy_lock);
1481
1482 if (filter_id == 0) {
1483 error = ENOMEM;
1484 } else {
1485 // Bloom filter is taken over by the new filter entry, clear the local pointer
1486 bloom_filter = NULL;
1487
1488 error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1489 if (error != 0) {
1490 NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1491 goto done;
1492 }
1493 }
1494
1495 done:
1496 *retval = error;
1497 if (error != 0 && bloom_filter != NULL) {
1498 uint8_t * __single filter_buffer = (uint8_t *)bloom_filter;
1499 kfree_data(filter_buffer, in_buffer_length);
1500 bloom_filter = NULL;
1501 }
1502 return error;
1503 }
1504
1505 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1506 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1507 {
1508 int error = 0;
1509
1510 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1511 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1512 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1513 error = EINVAL;
1514 goto done;
1515 }
1516
1517 u_int32_t filter_id;
1518 error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1519 if (error != 0) {
1520 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1521 goto done;
1522 }
1523
1524 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1525 bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1526 if (!removed) {
1527 error = ENOENT;
1528 }
1529 lck_rw_done(&necp_kernel_policy_lock);
1530
1531 done:
1532 *retval = error;
1533 return error;
1534 }
1535
1536 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1537 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1538 {
1539 #pragma unused(uap)
1540
1541 struct necp_domain_filter * __single filter = NULL;
1542 struct necp_domain_filter *temp_filter = NULL;
1543 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1544 if (os_ref_release_locked(&filter->refcount) == 0) {
1545 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1546 LIST_REMOVE(filter, chain);
1547 lck_rw_done(&necp_kernel_policy_lock);
1548 LIST_REMOVE(filter, owner_chain);
1549 net_bloom_filter_destroy(filter->filter);
1550 kfree_type(struct necp_domain_filter, filter);
1551 }
1552 }
1553
1554 *retval = 0;
1555 return 0;
1556 }
1557
1558 static int
necp_session_add_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1559 necp_session_add_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1560 {
1561 int error = 0;
1562
1563 struct necp_domain_trie_request *domain_trie_request = NULL;
1564 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1565 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1566
1567 if (in_buffer_length < sizeof(struct necp_domain_trie_request) ||
1568 in_buffer_length > NECP_MAX_DOMAIN_TRIE_SIZE ||
1569 uap->in_buffer == 0) {
1570 NECPLOG(LOG_ERR, "necp_session_add_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1571 error = EINVAL;
1572 goto done;
1573 }
1574
1575 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1576 NECPLOG(LOG_ERR, "necp_session_add_domain_trie buffer not large enough (%zu)", (size_t)out_buffer_length);
1577 error = EINVAL;
1578 goto done;
1579 }
1580
1581 domain_trie_request = (struct necp_domain_trie_request *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1582 if (domain_trie_request == NULL) {
1583 NECPLOG(LOG_ERR, "necp_session_add_domain_trie allocate trie request error (%zu)", in_buffer_length);
1584 error = ENOMEM;
1585 goto done;
1586 }
1587
1588 error = copyin(uap->in_buffer, domain_trie_request, in_buffer_length);
1589 if (error != 0) {
1590 NECPLOG(LOG_ERR, "necp_session_add_domain_trie filter copyin error (%d)", error);
1591 goto done;
1592 }
1593
1594 NECPLOG(LOG_INFO, "necp_session_add_domain_trie received %zu bytes <trie mem size %d>", in_buffer_length, domain_trie_request->total_mem_size);
1595
1596 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1597 u_int32_t id = necp_create_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, domain_trie_request, in_buffer_length);
1598 lck_rw_done(&necp_kernel_policy_lock);
1599
1600 if (id == 0) {
1601 error = ENOMEM;
1602 } else {
1603 error = copyout(&id, uap->out_buffer, sizeof(id));
1604 if (error != 0) {
1605 NECPLOG(LOG_ERR, "necp_session_add_domain_trie ID copyout error (%d)", error);
1606 goto done;
1607 }
1608 }
1609
1610 done:
1611 *retval = error;
1612 if (error != 0 && domain_trie_request != NULL) {
1613 uint8_t * __single domain_buffer = (uint8_t *)domain_trie_request;
1614 kfree_data(domain_buffer, in_buffer_length);
1615 domain_trie_request = NULL;
1616 }
1617 return error;
1618 }
1619
1620 static int
necp_session_remove_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1621 necp_session_remove_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1622 {
1623 int error = 0;
1624
1625 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1626 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1627 NECPLOG(LOG_ERR, "necp_session_remove_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1628 error = EINVAL;
1629 goto done;
1630 }
1631
1632 u_int32_t id;
1633 error = copyin(uap->in_buffer, &id, sizeof(id));
1634 if (error != 0) {
1635 NECPLOG(LOG_ERR, "necp_session_remove_domain_trie uuid copyin error (%d)", error);
1636 goto done;
1637 }
1638
1639 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1640 bool removed = necp_remove_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, id);
1641 if (!removed) {
1642 error = ENOENT;
1643 }
1644 lck_rw_done(&necp_kernel_policy_lock);
1645
1646 done:
1647 *retval = error;
1648 return error;
1649 }
1650
1651 static int
necp_session_remove_all_domain_tries(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1652 necp_session_remove_all_domain_tries(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1653 {
1654 #pragma unused(uap)
1655 struct necp_domain_trie* __single trie = NULL;
1656 struct necp_domain_trie* __single temp_trie = NULL;
1657 LIST_FOREACH_SAFE(trie, &session->domain_tries, owner_chain, temp_trie) {
1658 if (os_ref_release_locked(&trie->refcount) == 0) {
1659 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1660 LIST_REMOVE(trie, chain);
1661 lck_rw_done(&necp_kernel_policy_lock);
1662 LIST_REMOVE(trie, owner_chain);
1663 necp_free_domain_trie(trie);
1664 }
1665 }
1666 *retval = 0;
1667 return 0;
1668 }
1669
1670 static int
necp_session_trie_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1671 necp_session_trie_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1672 {
1673 #pragma unused(session)
1674
1675 int error = 0;
1676
1677 uint8_t request_buffer[2000] = { 0 };
1678 uint8_t *ptr = NULL;
1679 uint32_t count = 0;
1680 int output_length = 0;
1681
1682 lck_rw_lock_shared(&necp_kernel_policy_lock);
1683 count = necp_trie_count;
1684 lck_rw_done(&necp_kernel_policy_lock);
1685
1686 if (count == 0) {
1687 error = ENOENT;
1688 goto done;
1689 }
1690
1691 output_length = sizeof(count) + (count * sizeof(struct necp_domain_trie_request)); // first byte contains count
1692 if (output_length > uap->out_buffer_length) {
1693 NECPLOG(LOG_ERR, "necp_session_trie_dump_all out_buffer not large enough for %zu", (size_t)output_length);
1694 error = EINVAL;
1695 goto done;
1696 }
1697 if (output_length > sizeof(request_buffer)) {
1698 NECPLOG(LOG_ERR, "necp_session_trie_dump_all temporary buffer not large enough for %zu", (size_t)output_length);
1699 error = EINVAL;
1700 goto done;
1701 }
1702
1703 memcpy(request_buffer, (u_int8_t *)&count, sizeof(count));
1704 ptr = request_buffer + sizeof(count);
1705
1706 lck_rw_lock_shared(&necp_kernel_policy_lock);
1707 struct necp_domain_trie* __single trie = NULL;
1708 LIST_FOREACH(trie, &necp_global_domain_trie_list, chain) {
1709 if (trie->trie_request != NULL) {
1710 memcpy((u_int8_t *)ptr, (u_int8_t *)trie->trie_request, sizeof(struct necp_domain_trie_request));
1711 ptr += sizeof(struct necp_domain_trie_request);
1712 }
1713 }
1714 lck_rw_done(&necp_kernel_policy_lock);
1715
1716 error = copyout(request_buffer, uap->out_buffer, output_length);
1717
1718 done:
1719 *retval = error;
1720 return error;
1721 }
1722
1723 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1724 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1725 {
1726 struct fileproc * __single fp;
1727 int error = 0;
1728 int return_value = 0;
1729 struct necp_session * __single session = NULL;
1730
1731 error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1732 if (error != 0) {
1733 NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1734 return error;
1735 }
1736
1737 NECP_SESSION_LOCK(session);
1738
1739 if (session->proc_locked) {
1740 // Verify that the calling process is allowed to do actions
1741 uuid_t proc_uuid;
1742 proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1743 if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1744 error = EPERM;
1745 goto done;
1746 }
1747 } else {
1748 // If not locked, update the proc_uuid and proc_pid of the session
1749 proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1750 session->proc_pid = proc_pid(current_proc());
1751 }
1752
1753 u_int32_t action = uap->action;
1754 switch (action) {
1755 case NECP_SESSION_ACTION_POLICY_ADD: {
1756 return_value = necp_session_add_policy(session, uap, retval);
1757 break;
1758 }
1759 case NECP_SESSION_ACTION_POLICY_GET: {
1760 return_value = necp_session_get_policy(session, uap, retval);
1761 break;
1762 }
1763 case NECP_SESSION_ACTION_POLICY_DELETE: {
1764 return_value = necp_session_delete_policy(session, uap, retval);
1765 break;
1766 }
1767 case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1768 return_value = necp_session_apply_all(session, uap, retval);
1769 break;
1770 }
1771 case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1772 return_value = necp_session_list_all(session, uap, retval);
1773 break;
1774 }
1775 case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1776 return_value = necp_session_delete_all(session, uap, retval);
1777 break;
1778 }
1779 case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1780 return_value = necp_session_set_session_priority(session, uap, retval);
1781 break;
1782 }
1783 case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1784 return_value = necp_session_lock_to_process(session, uap, retval);
1785 break;
1786 }
1787 case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1788 return_value = 0; // Ignore
1789 break;
1790 }
1791 case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1792 return_value = 0; // Ignore
1793 break;
1794 }
1795 case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1796 return_value = necp_session_dump_all(session, uap, retval);
1797 break;
1798 }
1799 case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1800 return_value = necp_session_add_domain_filter(session, uap, retval);
1801 break;
1802 }
1803 case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1804 return_value = necp_session_remove_domain_filter(session, uap, retval);
1805 break;
1806 }
1807 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1808 return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1809 break;
1810 }
1811 case NECP_SESSION_ACTION_ADD_DOMAIN_TRIE: {
1812 return_value = necp_session_add_domain_trie(session, uap, retval);
1813 break;
1814 }
1815 case NECP_SESSION_ACTION_REMOVE_DOMAIN_TRIE: {
1816 return_value = necp_session_remove_domain_trie(session, uap, retval);
1817 break;
1818 }
1819 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_TRIES: {
1820 return_value = necp_session_remove_all_domain_tries(session, uap, retval);
1821 break;
1822 }
1823 case NECP_SESSION_ACTION_TRIE_DUMP_ALL: {
1824 return_value = necp_session_trie_dump_all(session, uap, retval);
1825 break;
1826 }
1827 default: {
1828 NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1829 return_value = EINVAL;
1830 break;
1831 }
1832 }
1833
1834 done:
1835 NECP_SESSION_UNLOCK(session);
1836 fp_drop(p, uap->necp_fd, fp, 0);
1837 return return_value;
1838 }
1839
1840 struct necp_resolver_key_state {
1841 const struct ccdigest_info *digest_info;
1842 uint8_t key[CCSHA256_OUTPUT_SIZE];
1843 };
1844 static struct necp_resolver_key_state s_necp_resolver_key_state;
1845
1846 static void
necp_generate_resolver_key(void)1847 necp_generate_resolver_key(void)
1848 {
1849 s_necp_resolver_key_state.digest_info = ccsha256_di();
1850 cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1851 }
1852
1853 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)1854 necp_sign_update_context(const struct ccdigest_info *di,
1855 cchmac_ctx_t ctx,
1856 uuid_t client_id,
1857 u_int32_t sign_type,
1858 u_int8_t *data,
1859 size_t data_length)
1860 {
1861 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1862 const char * __null_terminated context_string = "NECP Resolver Binder";
1863 uint8_t separator = 0;
1864 cchmac_update(di, ctx, sizeof(context), context);
1865 cchmac_update(di, ctx, strlen(context_string), __unsafe_null_terminated_to_indexable(context_string));
1866 cchmac_update(di, ctx, sizeof(separator), &separator);
1867 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1868 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1869 cchmac_update(di, ctx, data_length, data);
1870 }
1871
1872 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)1873 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1874 u_int8_t *data, size_t data_length,
1875 u_int8_t *tag, size_t *out_tag_length)
1876 {
1877 if (s_necp_resolver_key_state.digest_info == NULL) {
1878 return EINVAL;
1879 }
1880
1881 if (data == NULL ||
1882 data_length == 0 ||
1883 tag == NULL ||
1884 out_tag_length == NULL) {
1885 return EINVAL;
1886 }
1887
1888 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1889 if (*out_tag_length < required_tag_length) {
1890 return ERANGE;
1891 }
1892
1893 *out_tag_length = required_tag_length;
1894
1895 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1896 s_necp_resolver_key_state.digest_info->block_size, ctx);
1897 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1898 sizeof(s_necp_resolver_key_state.key),
1899 s_necp_resolver_key_state.key);
1900 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1901 ctx, client_id, sign_type, data, data_length);
1902 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1903
1904 return 0;
1905 }
1906
1907 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)1908 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1909 u_int8_t * __sized_by(data_length)data, size_t data_length,
1910 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1911 {
1912 if (s_necp_resolver_key_state.digest_info == NULL) {
1913 return false;
1914 }
1915
1916 if (data == NULL ||
1917 data_length == 0 ||
1918 tag == NULL ||
1919 tag_length == 0) {
1920 return false;
1921 }
1922
1923 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1924 if (tag_length != required_tag_length) {
1925 return false;
1926 }
1927
1928 uint8_t actual_tag[required_tag_length];
1929
1930 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1931 s_necp_resolver_key_state.digest_info->block_size, ctx);
1932 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1933 sizeof(s_necp_resolver_key_state.key),
1934 s_necp_resolver_key_state.key);
1935 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1936 ctx, client_id, sign_type, data, data_length);
1937 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
1938
1939 return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
1940 }
1941
1942 struct necp_application_id_key_state {
1943 const struct ccdigest_info *digest_info;
1944 uint8_t key[CCSHA256_OUTPUT_SIZE];
1945 };
1946 static struct necp_application_id_key_state s_necp_application_id_key_state;
1947
1948 static void
necp_generate_application_id_key(void)1949 necp_generate_application_id_key(void)
1950 {
1951 s_necp_application_id_key_state.digest_info = ccsha256_di();
1952 cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
1953 }
1954
1955 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)1956 necp_sign_application_id_update_context(const struct ccdigest_info *di,
1957 cchmac_ctx_t ctx,
1958 uuid_t client_id,
1959 u_int32_t sign_type)
1960 {
1961 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1962 const char context_string[] = "NECP Application ID";
1963 uint8_t separator = 0;
1964 cchmac_update(di, ctx, sizeof(context), context);
1965 cchmac_update(di, ctx, sizeof(context_string) - 1, context_string);
1966 cchmac_update(di, ctx, sizeof(separator), &separator);
1967 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1968 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1969 }
1970
1971 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)1972 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
1973 u_int8_t *__counted_by(*out_tag_length)tag, size_t *out_tag_length)
1974 {
1975 if (s_necp_application_id_key_state.digest_info == NULL) {
1976 return EINVAL;
1977 }
1978
1979 if (tag == NULL ||
1980 out_tag_length == NULL) {
1981 return EINVAL;
1982 }
1983
1984 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1985 if (*out_tag_length < required_tag_length) {
1986 return ERANGE;
1987 }
1988
1989 *out_tag_length = required_tag_length;
1990
1991 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1992 s_necp_application_id_key_state.digest_info->block_size, ctx);
1993 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
1994 sizeof(s_necp_application_id_key_state.key),
1995 s_necp_application_id_key_state.key);
1996 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
1997 ctx, client_id, sign_type);
1998 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
1999
2000 return 0;
2001 }
2002
2003 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)2004 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
2005 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
2006 {
2007 if (s_necp_application_id_key_state.digest_info == NULL) {
2008 return false;
2009 }
2010
2011 if (tag == NULL ||
2012 tag_length == 0) {
2013 return false;
2014 }
2015
2016 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2017 if (tag_length != required_tag_length) {
2018 return false;
2019 }
2020
2021 uint8_t actual_tag[required_tag_length];
2022
2023 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2024 s_necp_application_id_key_state.digest_info->block_size, ctx);
2025 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2026 sizeof(s_necp_application_id_key_state.key),
2027 s_necp_application_id_key_state.key);
2028 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2029 ctx, client_id, sign_type);
2030 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
2031
2032 return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
2033 }
2034
2035 void
necp_init(void)2036 necp_init(void)
2037 {
2038 necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
2039 necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
2040
2041 necp_client_init();
2042
2043 TAILQ_INIT(&necp_session_list);
2044
2045 LIST_INIT(&necp_kernel_socket_policies);
2046 LIST_INIT(&necp_kernel_ip_output_policies);
2047
2048 LIST_INIT(&necp_account_id_list);
2049
2050 LIST_INIT(&necp_agent_uuid_id_list);
2051
2052 LIST_INIT(&necp_route_rules);
2053 LIST_INIT(&necp_aggregate_route_rules);
2054
2055 LIST_INIT(&necp_global_domain_filter_list);
2056 LIST_INIT(&necp_global_domain_trie_list);
2057
2058 necp_generate_resolver_key();
2059 necp_generate_application_id_key();
2060
2061 necp_uuid_app_id_hashtbl = __unsafe_forge_bidi_indexable(struct necp_uuid_id_mapping_head *,
2062 hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask),
2063 NECP_UUID_APP_ID_HASH_SIZE * sizeof(void*));
2064 necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
2065 necp_num_uuid_app_id_mappings = 0;
2066 necp_uuid_app_id_mappings_dirty = FALSE;
2067
2068 necp_kernel_application_policies_condition_mask = 0;
2069 necp_kernel_socket_policies_condition_mask = 0;
2070 necp_kernel_ip_output_policies_condition_mask = 0;
2071
2072 necp_kernel_application_policies_count = 0;
2073 necp_kernel_socket_policies_count = 0;
2074 necp_kernel_socket_policies_non_app_count = 0;
2075 necp_kernel_ip_output_policies_count = 0;
2076 necp_kernel_ip_output_policies_non_id_count = 0;
2077
2078 necp_kernel_socket_policies_gencount = 1;
2079
2080 memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
2081 memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
2082 necp_kernel_socket_policies_app_layer_map = NULL;
2083
2084 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
2085 necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
2086 }
2087
2088 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)2089 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
2090 {
2091 struct kev_msg ev_msg;
2092 memset(&ev_msg, 0, sizeof(ev_msg));
2093
2094 ev_msg.vendor_code = KEV_VENDOR_APPLE;
2095 ev_msg.kev_class = KEV_NETWORK_CLASS;
2096 ev_msg.kev_subclass = KEV_NECP_SUBCLASS;
2097 ev_msg.event_code = KEV_NECP_POLICIES_CHANGED;
2098
2099 ev_msg.dv[0].data_ptr = necp_event_data;
2100 ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
2101 ev_msg.dv[1].data_length = 0;
2102
2103 kev_post_msg(&ev_msg);
2104 }
2105
2106 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)2107 necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor, u_int8_t type, u_int32_t length,
2108 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2109 {
2110 if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
2111 NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
2112 return false;
2113 }
2114 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2115 if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
2116 (uintptr_t)(next_tlv - buffer) > buffer_length) { // make sure the next TLV has enough room in buffer
2117 NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
2118 length, buffer_length);
2119 return false;
2120 }
2121 return true;
2122 }
2123
2124 u_int8_t * __counted_by(0)
2125 necp_buffer_write_tlv_if_different(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2126 u_int32_t length, const void * __sized_by(length)value, bool *updated,
2127 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2128 {
2129 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2130 u_int8_t * cursor = buffer + (cursor_ - buffer);
2131 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2132 // If we can't fit this TLV, return the current cursor
2133 return cursor;
2134 }
2135 u_int8_t * __indexable next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2136 if (*updated || *(u_int8_t *)(cursor) != type) {
2137 *(u_int8_t *)(cursor) = type;
2138 *updated = TRUE;
2139 }
2140 if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
2141 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2142 *updated = TRUE;
2143 }
2144 if (length > 0) {
2145 if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
2146 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2147 *updated = TRUE;
2148 }
2149 }
2150 return next_tlv;
2151 }
2152
2153 u_int8_t * __counted_by(0)
2154 necp_buffer_write_tlv(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2155 u_int32_t length, const void * __sized_by(length)value,
2156 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2157 {
2158 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2159 u_int8_t * cursor = buffer + (cursor_ - buffer);
2160 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2161 return NULL;
2162 }
2163 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2164 *(u_int8_t *)(cursor) = type;
2165 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2166 if (length > 0) {
2167 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2168 }
2169
2170 return next_tlv;
2171 }
2172
2173 static u_int8_t * __counted_by(0)
2174 necp_buffer_write_tlv_with_flags(u_int8_t * __counted_by(0)cursor_, u_int8_t type, u_int8_t flags,
2175 u_int32_t length, const void * __sized_by(length)value,
2176 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2177 {
2178 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2179 // Add one extra byte to 'length' to account for the flags byte for validation.
2180 u_int8_t * cursor = buffer + (cursor_ - buffer);
2181 if (!necp_buffer_write_tlv_validate(cursor, type, length + 1, buffer, buffer_length)) {
2182 return NULL;
2183 }
2184 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(flags) + sizeof(length) + length);
2185
2186 // TLV with flags format: type, length, flags, value (added 1 byte for the leading flags)
2187 *(u_int8_t *)(cursor) = type;
2188 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2189 *(u_int8_t *)(cursor + sizeof(type) + sizeof(length)) = flags;
2190 if (length > 0) {
2191 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length) + sizeof(flags)), value, length);
2192 }
2193
2194 return next_tlv;
2195 }
2196
2197 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)2198 necp_buffer_get_tlv_type(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2199 {
2200 u_int8_t * __indexable type = NULL;
2201 uint64_t end_offset = 0;
2202
2203 if (buffer == NULL ||
2204 os_add_overflow(tlv_offset, sizeof(u_int8_t), &end_offset) || buffer_length < end_offset) {
2205 return 0;
2206 }
2207
2208 type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
2209 return type ? *type : 0;
2210 }
2211
2212 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)2213 necp_buffer_get_tlv_length(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2214 {
2215 u_int32_t * __indexable length = NULL;
2216 uint64_t end_offset = 0;
2217
2218 if (buffer == NULL ||
2219 os_add_overflow(tlv_offset, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2220 return 0;
2221 }
2222
2223 length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
2224 return length ? *length : 0;
2225 }
2226
2227 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)2228 __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)
2229 {
2230 u_int8_t * __indexable value = NULL;
2231 uint64_t end_offset = 0;
2232
2233 if (buffer == NULL) {
2234 return NULL;
2235 }
2236
2237 u_int32_t length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2238 if (length == 0) {
2239 return NULL;
2240 }
2241
2242 if (os_add3_overflow(tlv_offset, length, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2243 return NULL;
2244 }
2245
2246 if (value_size) {
2247 *value_size = length;
2248 }
2249
2250 value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2251 return value;
2252 }
2253
2254 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)2255 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)
2256 {
2257 if (err != NULL) {
2258 *err = ENOENT;
2259 }
2260 if (offset < 0) {
2261 if (err != NULL) {
2262 *err = EINVAL;
2263 }
2264 return -1;
2265 }
2266 int cursor = offset;
2267 int next_cursor;
2268 u_int32_t curr_length;
2269 u_int8_t curr_type;
2270
2271 while (TRUE) {
2272 if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
2273 return -1;
2274 }
2275 if (!next) {
2276 curr_type = necp_buffer_get_tlv_type(buffer, buffer_length, cursor);
2277 } else {
2278 next = 0;
2279 curr_type = NECP_TLV_NIL;
2280 }
2281 curr_length = necp_buffer_get_tlv_length(buffer, buffer_length, cursor);
2282 if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
2283 return -1;
2284 }
2285
2286 next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
2287 if (curr_type == type) {
2288 // check if entire TLV fits inside buffer
2289 if (((u_int32_t)next_cursor) <= buffer_length) {
2290 if (err != NULL) {
2291 *err = 0;
2292 }
2293 return cursor;
2294 } else {
2295 return -1;
2296 }
2297 }
2298 cursor = next_cursor;
2299 }
2300 }
2301
2302 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)2303 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)
2304 {
2305 int cursor = -1;
2306 if (buffer != NULL) {
2307 cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2308 }
2309 return cursor;
2310 }
2311
2312 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)2313 necp_get_tlv_at_offset(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2314 int tlv_offset, u_int32_t out_buffer_length, void * __indexable out_buffer, u_int32_t *value_size)
2315 {
2316 if (buffer == NULL) {
2317 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2318 return EINVAL;
2319 }
2320
2321 // Handle buffer parsing
2322
2323 // Validate that buffer has enough room for any TLV
2324 if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2325 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2326 buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2327 return EINVAL;
2328 }
2329
2330 // Validate that buffer has enough room for this TLV
2331 u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2332 if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2333 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2334 tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2335 return EINVAL;
2336 }
2337
2338 if (out_buffer != NULL && out_buffer_length > 0) {
2339 // Validate that out buffer is large enough for value
2340 if (out_buffer_length < tlv_length) {
2341 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2342 out_buffer_length, tlv_length);
2343 return EINVAL;
2344 }
2345
2346 // Get value pointer
2347 u_int8_t * __indexable tlv_value = necp_buffer_get_tlv_value(buffer, buffer_length, tlv_offset, NULL);
2348 if (tlv_value == NULL) {
2349 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2350 return ENOENT;
2351 }
2352
2353 // Copy value
2354 memcpy(out_buffer, tlv_value, tlv_length);
2355 }
2356
2357 // Copy out length
2358 if (value_size != NULL) {
2359 *value_size = tlv_length;
2360 }
2361
2362 return 0;
2363 }
2364
2365 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)2366 necp_get_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2367 int offset, u_int8_t type, u_int32_t buff_len, void * __indexable buff, u_int32_t *value_size)
2368 {
2369 int error = 0;
2370
2371 int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2372 if (tlv_offset < 0) {
2373 return error;
2374 }
2375
2376 return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2377 }
2378
2379 // Session Management
2380
2381 static struct necp_session *
necp_create_session(void)2382 necp_create_session(void)
2383 {
2384 struct necp_session *new_session = NULL;
2385
2386 new_session = kalloc_type(struct necp_session,
2387 Z_WAITOK | Z_ZERO | Z_NOFAIL);
2388
2389 new_session->necp_fd_type = necp_fd_type_session;
2390 new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2391 new_session->dirty = FALSE;
2392 LIST_INIT(&new_session->policies);
2393 LIST_INIT(&new_session->domain_filters);
2394 LIST_INIT(&new_session->domain_tries);
2395 lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2396
2397 // Take the lock
2398 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2399
2400 // Find the next available control unit
2401 u_int32_t control_unit = 1;
2402 struct necp_session *next_session = NULL;
2403 TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2404 if (next_session->control_unit > control_unit) {
2405 // Found a gap, grab this control unit
2406 break;
2407 }
2408
2409 // Try the next control unit, loop around
2410 control_unit = next_session->control_unit + 1;
2411 }
2412
2413 new_session->control_unit = control_unit;
2414 new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2415
2416 if (next_session != NULL) {
2417 TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2418 } else {
2419 TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2420 }
2421
2422 necp_session_count++;
2423 lck_rw_done(&necp_kernel_policy_lock);
2424
2425 if (necp_debug) {
2426 NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2427 }
2428
2429 return new_session;
2430 }
2431
2432 static void
necp_delete_session(struct necp_session * session)2433 necp_delete_session(struct necp_session *session)
2434 {
2435 if (session != NULL) {
2436 struct necp_domain_filter * __single filter = NULL;
2437 struct necp_domain_filter *temp_filter = NULL;
2438 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2439 if (os_ref_release_locked(&filter->refcount) == 0) {
2440 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2441 LIST_REMOVE(filter, chain);
2442 lck_rw_done(&necp_kernel_policy_lock);
2443 LIST_REMOVE(filter, owner_chain);
2444 net_bloom_filter_destroy(filter->filter);
2445 kfree_type(struct necp_domain_filter, filter);
2446 }
2447 }
2448 if (necp_debug) {
2449 NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2450 }
2451
2452 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2453 TAILQ_REMOVE(&necp_session_list, session, chain);
2454 necp_session_count--;
2455 lck_rw_done(&necp_kernel_policy_lock);
2456
2457 lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2458 kfree_type(struct necp_session, session);
2459 }
2460 }
2461
2462 // Session Policy Management
2463
2464 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2465 necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2466 {
2467 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2468 }
2469
2470 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2471 necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2472 {
2473 return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2474 }
2475
2476 static inline u_int8_t * __indexable
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2477 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2478 {
2479 return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2480 }
2481
2482 static bool
necp_policy_result_requires_route_rules(u_int8_t * __sized_by (length)buffer,u_int32_t length)2483 necp_policy_result_requires_route_rules(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2484 {
2485 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2486 if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2487 return TRUE;
2488 }
2489 return FALSE;
2490 }
2491
2492 static inline bool
_necp_address_is_valid(struct sockaddr * address)2493 _necp_address_is_valid(struct sockaddr *address)
2494 {
2495 if (address->sa_family == AF_INET) {
2496 return address->sa_len == sizeof(struct sockaddr_in);
2497 } else if (address->sa_family == AF_INET6) {
2498 return address->sa_len == sizeof(struct sockaddr_in6);
2499 } else {
2500 return FALSE;
2501 }
2502 }
2503
2504 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2505
2506 static bool
necp_policy_result_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,bool * is_pass_skip)2507 necp_policy_result_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, bool *is_pass_skip)
2508 {
2509 bool validated = FALSE;
2510 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2511 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2512 *is_pass_skip = FALSE;
2513 switch (type) {
2514 case NECP_POLICY_RESULT_PASS: {
2515 *is_pass_skip = TRUE;
2516 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2517 validated = TRUE;
2518 }
2519 break;
2520 }
2521 case NECP_POLICY_RESULT_DROP: {
2522 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2523 validated = TRUE;
2524 }
2525 break;
2526 }
2527 case NECP_POLICY_RESULT_ROUTE_RULES:
2528 case NECP_POLICY_RESULT_SCOPED_DIRECT:
2529 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2530 validated = TRUE;
2531 break;
2532 }
2533 case NECP_POLICY_RESULT_SKIP:
2534 *is_pass_skip = TRUE;
2535 case NECP_POLICY_RESULT_SOCKET_DIVERT:
2536 case NECP_POLICY_RESULT_SOCKET_FILTER: {
2537 if (parameter_length >= sizeof(u_int32_t)) {
2538 validated = TRUE;
2539 }
2540 break;
2541 }
2542 case NECP_POLICY_RESULT_IP_TUNNEL: {
2543 if (parameter_length > sizeof(u_int32_t)) {
2544 validated = TRUE;
2545 }
2546 break;
2547 }
2548 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2549 if (parameter_length > 0) {
2550 validated = TRUE;
2551 }
2552 break;
2553 }
2554 case NECP_POLICY_RESULT_USE_NETAGENT:
2555 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2556 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2557 if (parameter_length >= sizeof(uuid_t)) {
2558 validated = TRUE;
2559 }
2560 break;
2561 }
2562 case NECP_POLICY_RESULT_REMOVE_NETAGENT_TYPE: {
2563 if (parameter_length >= sizeof(struct necp_policy_condition_agent_type)) {
2564 validated = TRUE;
2565 }
2566 break;
2567 }
2568 default: {
2569 validated = FALSE;
2570 break;
2571 }
2572 }
2573
2574 if (necp_debug) {
2575 NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2576 }
2577
2578 return validated;
2579 }
2580
2581 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2582 necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2583 {
2584 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2585 }
2586
2587 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2588 necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2589 {
2590 return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2591 }
2592
2593 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2594 necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2595 {
2596 return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2597 }
2598
2599 static inline u_int8_t * __indexable
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2600 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2601 {
2602 return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2603 }
2604
2605 static inline bool
necp_policy_condition_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2606 necp_policy_condition_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2607 {
2608 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2609 }
2610
2611 static inline bool
necp_policy_condition_is_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2612 necp_policy_condition_is_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2613 {
2614 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2615 }
2616
2617 static inline bool
necp_policy_condition_is_real_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2618 necp_policy_condition_is_real_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2619 {
2620 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2621 }
2622
2623 static inline bool
necp_policy_condition_requires_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2624 necp_policy_condition_requires_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2625 {
2626 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2627 return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2628 }
2629
2630 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2631 necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2632 {
2633 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2634 u_int32_t condition_length = 0;
2635 pid_t *condition_value = NULL;
2636
2637 if (type == NECP_POLICY_CONDITION_PID) {
2638 condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2639 if (condition_length >= sizeof(pid_t)) {
2640 condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2641 return *condition_value == 0;
2642 }
2643 }
2644 return false;
2645 }
2646
2647 static bool
necp_policy_condition_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,u_int8_t policy_result_type)2648 necp_policy_condition_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, u_int8_t policy_result_type)
2649 {
2650 bool validated = FALSE;
2651 bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2652 policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2653 policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2654 policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2655 policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2656 policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2657 policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2658 policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2659 policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT ||
2660 policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT_TYPE) ? TRUE : FALSE;
2661 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2662 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2663 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2664 u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2665 switch (type) {
2666 case NECP_POLICY_CONDITION_APPLICATION:
2667 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2668 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2669 condition_length >= sizeof(uuid_t) &&
2670 condition_value != NULL &&
2671 !uuid_is_null(condition_value)) {
2672 validated = TRUE;
2673 }
2674 break;
2675 }
2676 case NECP_POLICY_CONDITION_DOMAIN:
2677 case NECP_POLICY_CONDITION_ACCOUNT:
2678 case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2679 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2680 case NECP_POLICY_CONDITION_URL: {
2681 if (condition_length > 0) {
2682 validated = TRUE;
2683 }
2684 break;
2685 }
2686 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2687 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2688 validated = TRUE;
2689 }
2690 break;
2691 }
2692 case NECP_POLICY_CONDITION_DEFAULT:
2693 case NECP_POLICY_CONDITION_ALL_INTERFACES:
2694 case NECP_POLICY_CONDITION_ENTITLEMENT:
2695 case NECP_POLICY_CONDITION_HAS_CLIENT:
2696 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
2697 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2698 validated = TRUE;
2699 }
2700 break;
2701 }
2702 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2703 if (condition_length == 0 || condition_length >= sizeof(u_int8_t)) {
2704 validated = TRUE;
2705 }
2706 break;
2707 }
2708 case NECP_POLICY_CONDITION_SDK_VERSION: {
2709 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2710 condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2711 validated = TRUE;
2712 }
2713 break;
2714 }
2715 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2716 if (condition_length >= sizeof(u_int16_t)) {
2717 validated = TRUE;
2718 }
2719 break;
2720 }
2721 case NECP_POLICY_CONDITION_PID: {
2722 if (condition_length >= sizeof(pid_t) &&
2723 condition_value != NULL) {
2724 validated = TRUE;
2725 }
2726 break;
2727 }
2728 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2729 if (condition_length >= sizeof(u_int32_t)) {
2730 validated = TRUE;
2731 }
2732 break;
2733 }
2734 case NECP_POLICY_CONDITION_UID:
2735 case NECP_POLICY_CONDITION_REAL_UID: {
2736 if (condition_length >= sizeof(uid_t)) {
2737 validated = TRUE;
2738 }
2739 break;
2740 }
2741 case NECP_POLICY_CONDITION_LOCAL_ADDR:
2742 case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2743 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2744 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2745 validated = TRUE;
2746 }
2747 break;
2748 }
2749 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2750 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2751 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2752 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2753 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2754 validated = TRUE;
2755 }
2756 break;
2757 }
2758 case NECP_POLICY_CONDITION_AGENT_TYPE: {
2759 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2760 condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2761 validated = TRUE;
2762 }
2763 break;
2764 }
2765 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2766 if (condition_length >= sizeof(u_int16_t)) {
2767 validated = TRUE;
2768 }
2769 break;
2770 }
2771 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2772 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2773 if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2774 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2775 validated = TRUE;
2776 }
2777 break;
2778 }
2779 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2780 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2781 if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2782 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2783 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2784 validated = TRUE;
2785 }
2786 break;
2787 }
2788 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2789 if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2790 validated = TRUE;
2791 }
2792 break;
2793 }
2794 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2795 validated = TRUE;
2796 break;
2797 }
2798 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2799 validated = TRUE;
2800 break;
2801 }
2802 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2803 if (condition_length >= sizeof(u_int16_t)) {
2804 u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2805 if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2806 validated = TRUE;
2807 }
2808 }
2809 break;
2810 }
2811 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2812 validated = TRUE;
2813 break;
2814 }
2815 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
2816 validated = TRUE;
2817 break;
2818 }
2819 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2820 validated = TRUE;
2821 break;
2822 }
2823 case NECP_POLICY_CONDITION_SCHEME_PORT: {
2824 if (condition_length >= sizeof(u_int16_t)) {
2825 validated = TRUE;
2826 }
2827 break;
2828 }
2829 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2830 if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2831 validated = TRUE;
2832 }
2833 break;
2834 }
2835 default: {
2836 validated = FALSE;
2837 break;
2838 }
2839 }
2840
2841 if (necp_debug) {
2842 NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2843 }
2844
2845 return validated;
2846 }
2847
2848 static bool
necp_policy_route_rule_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2849 necp_policy_route_rule_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2850 {
2851 return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2852 necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2853 }
2854
2855 static bool
necp_policy_route_rule_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2856 necp_policy_route_rule_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2857 {
2858 bool validated = FALSE;
2859 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2860 switch (type) {
2861 case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2862 validated = TRUE;
2863 break;
2864 }
2865 case NECP_ROUTE_RULE_DENY_INTERFACE: {
2866 validated = TRUE;
2867 break;
2868 }
2869 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2870 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2871 validated = (rule_length >= sizeof(u_int32_t));
2872 break;
2873 }
2874 case NECP_ROUTE_RULE_QOS_MARKING: {
2875 validated = TRUE;
2876 break;
2877 }
2878 case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2879 validated = TRUE;
2880 break;
2881 }
2882 case NECP_ROUTE_RULE_USE_NETAGENT:
2883 case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2884 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2885 validated = (rule_length >= sizeof(uuid_t));
2886 break;
2887 }
2888 case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2889 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2890 validated = (rule_length >= sizeof(uint32_t));
2891 break;
2892 }
2893 default: {
2894 validated = FALSE;
2895 break;
2896 }
2897 }
2898
2899 if (necp_debug) {
2900 NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2901 }
2902
2903 return validated;
2904 }
2905
2906 static int
necp_get_posix_error_for_necp_error(int response_error)2907 necp_get_posix_error_for_necp_error(int response_error)
2908 {
2909 switch (response_error) {
2910 case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2911 case NECP_ERROR_INVALID_TLV:
2912 case NECP_ERROR_POLICY_RESULT_INVALID:
2913 case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2914 case NECP_ERROR_ROUTE_RULES_INVALID: {
2915 return EINVAL;
2916 }
2917 case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2918 return ENOENT;
2919 }
2920 case NECP_ERROR_INVALID_PROCESS: {
2921 return EPERM;
2922 }
2923 case NECP_ERROR_INTERNAL:
2924 default: {
2925 return ENOMEM;
2926 }
2927 }
2928 }
2929
2930 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)2931 necp_handle_policy_add(struct necp_session *session,
2932 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
2933 {
2934 bool has_default_condition = FALSE;
2935 bool has_non_default_condition = FALSE;
2936 bool has_application_condition = FALSE;
2937 bool has_real_application_condition = FALSE;
2938 bool requires_application_condition = FALSE;
2939 bool has_kernel_pid = FALSE;
2940 bool is_pass_skip = FALSE;
2941 u_int32_t conditions_array_size = 0;
2942 u_int8_t *conditions_array = NULL;
2943 int conditions_array_cursor;
2944
2945 bool has_default_route_rule = FALSE;
2946 u_int32_t route_rules_array_size = 0;
2947 u_int8_t *route_rules_array = NULL;
2948 int route_rules_array_cursor;
2949
2950 int cursor;
2951 int error = 0;
2952 u_int32_t response_error = NECP_ERROR_INTERNAL;
2953
2954 necp_policy_order order = 0;
2955 struct necp_session_policy *policy = NULL;
2956 u_int32_t policy_result_size = 0;
2957 u_int8_t *policy_result = NULL;
2958
2959 // Read policy order
2960 error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
2961 if (error) {
2962 NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
2963 response_error = NECP_ERROR_INVALID_TLV;
2964 goto fail;
2965 }
2966
2967 // Read policy result
2968 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
2969 if (error || cursor < 0) {
2970 NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
2971 response_error = NECP_ERROR_INVALID_TLV;
2972 goto fail;
2973 }
2974
2975 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
2976 if (error || policy_result_size == 0) {
2977 NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
2978 response_error = NECP_ERROR_INVALID_TLV;
2979 goto fail;
2980 }
2981 if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
2982 NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
2983 response_error = NECP_ERROR_INVALID_TLV;
2984 goto fail;
2985 }
2986 policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
2987 if (policy_result == NULL) {
2988 NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
2989 response_error = NECP_ERROR_INTERNAL;
2990 goto fail;
2991 }
2992 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
2993 if (error) {
2994 NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
2995 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2996 goto fail;
2997 }
2998 if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
2999 NECPLOG0(LOG_ERR, "Failed to validate policy result");
3000 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3001 goto fail;
3002 }
3003
3004 if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
3005 // Read route rules conditions
3006
3007 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3008 cursor >= 0;
3009 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3010 u_int32_t route_rule_size = 0;
3011 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3012 if (os_add_overflow(route_rules_array_size,
3013 (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
3014 &route_rules_array_size)) {
3015 NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
3016 response_error = NECP_ERROR_INVALID_TLV;
3017 goto fail;
3018 }
3019 }
3020
3021 if (route_rules_array_size == 0) {
3022 NECPLOG0(LOG_ERR, "Failed to get policy route rules");
3023 response_error = NECP_ERROR_INVALID_TLV;
3024 goto fail;
3025 }
3026 if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
3027 NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
3028 response_error = NECP_ERROR_INVALID_TLV;
3029 goto fail;
3030 }
3031 route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
3032 if (route_rules_array == NULL) {
3033 NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
3034 response_error = NECP_ERROR_INTERNAL;
3035 goto fail;
3036 }
3037
3038 route_rules_array_cursor = 0;
3039 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3040 cursor >= 0;
3041 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3042 u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
3043 u_int32_t route_rule_size = 0;
3044 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3045 if (route_rule_size > 0 &&
3046 (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
3047 // Add type
3048 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
3049 route_rules_array_cursor += sizeof(route_rule_type);
3050
3051 // Add length
3052 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
3053 route_rules_array_cursor += sizeof(route_rule_size);
3054
3055 // Add value
3056 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
3057
3058 if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3059 NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
3060 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3061 goto fail;
3062 }
3063
3064 if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3065 if (has_default_route_rule) {
3066 NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
3067 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3068 goto fail;
3069 }
3070 has_default_route_rule = TRUE;
3071 }
3072
3073 route_rules_array_cursor += route_rule_size;
3074 }
3075 }
3076 }
3077
3078 // Read policy conditions
3079 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3080 cursor >= 0;
3081 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3082 u_int32_t condition_size = 0;
3083 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3084
3085 if (condition_size > 0) {
3086 if (os_add_overflow(conditions_array_size,
3087 (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
3088 &conditions_array_size)) {
3089 NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
3090 response_error = NECP_ERROR_INVALID_TLV;
3091 goto fail;
3092 }
3093 }
3094 }
3095
3096 if (conditions_array_size == 0) {
3097 NECPLOG0(LOG_ERR, "Failed to get policy conditions");
3098 response_error = NECP_ERROR_INVALID_TLV;
3099 goto fail;
3100 }
3101 if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
3102 NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
3103 response_error = NECP_ERROR_INVALID_TLV;
3104 goto fail;
3105 }
3106 conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
3107 if (conditions_array == NULL) {
3108 NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
3109 response_error = NECP_ERROR_INTERNAL;
3110 goto fail;
3111 }
3112
3113 conditions_array_cursor = 0;
3114 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3115 cursor >= 0;
3116 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3117 u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
3118 u_int32_t condition_size = 0;
3119 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3120 if (condition_size > 0 &&
3121 (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
3122 // Add type
3123 memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
3124 conditions_array_cursor += sizeof(condition_type);
3125
3126 // Add length
3127 memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
3128 conditions_array_cursor += sizeof(condition_size);
3129
3130 // Add value
3131 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
3132 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))) {
3133 NECPLOG0(LOG_ERR, "Failed to validate policy condition");
3134 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3135 goto fail;
3136 }
3137
3138 if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
3139 has_default_condition = TRUE;
3140 } else {
3141 has_non_default_condition = TRUE;
3142 }
3143 if (has_default_condition && has_non_default_condition) {
3144 NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
3145 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3146 goto fail;
3147 }
3148
3149 if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
3150 has_application_condition = TRUE;
3151 }
3152
3153 if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
3154 has_real_application_condition = TRUE;
3155 }
3156
3157 if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
3158 requires_application_condition = TRUE;
3159 }
3160
3161 if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
3162 has_kernel_pid = TRUE;
3163 }
3164
3165 conditions_array_cursor += condition_size;
3166 }
3167 }
3168
3169 if (requires_application_condition && !has_application_condition) {
3170 NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
3171 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3172 goto fail;
3173 }
3174
3175 if (has_kernel_pid && !is_pass_skip) {
3176 NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
3177 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3178 goto fail;
3179 }
3180
3181 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) {
3182 response_error = NECP_ERROR_INTERNAL;
3183 goto fail;
3184 }
3185
3186 return policy->local_id;
3187
3188 fail:
3189 if (policy_result != NULL) {
3190 kfree_data_sized_by(policy_result, policy_result_size);
3191 }
3192 if (conditions_array != NULL) {
3193 kfree_data_sized_by(conditions_array, conditions_array_size);
3194 }
3195 if (route_rules_array != NULL) {
3196 kfree_data_sized_by(route_rules_array, route_rules_array_size);
3197 }
3198
3199 if (return_error != NULL) {
3200 *return_error = necp_get_posix_error_for_necp_error(response_error);
3201 }
3202 return 0;
3203 }
3204
3205 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)3206 necp_policy_get_new_id(struct necp_session *session)
3207 {
3208 session->last_policy_id++;
3209 if (session->last_policy_id < 1) {
3210 session->last_policy_id = 1;
3211 }
3212
3213 necp_policy_id newid = session->last_policy_id;
3214
3215 if (newid == 0) {
3216 NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
3217 return 0;
3218 }
3219
3220 return newid;
3221 }
3222
3223 /*
3224 * For the policy dump response this is the structure:
3225 *
3226 * <NECP_PACKET_HEADER>
3227 * {
3228 * type : NECP_TLV_POLICY_DUMP
3229 * length : ...
3230 * value :
3231 * {
3232 * {
3233 * type : NECP_TLV_POLICY_ID
3234 * len : ...
3235 * value : ...
3236 * }
3237 * {
3238 * type : NECP_TLV_POLICY_ORDER
3239 * len : ...
3240 * value : ...
3241 * }
3242 * {
3243 * type : NECP_TLV_POLICY_RESULT_STRING
3244 * len : ...
3245 * value : ...
3246 * }
3247 * {
3248 * type : NECP_TLV_POLICY_OWNER
3249 * len : ...
3250 * value : ...
3251 * }
3252 * {
3253 * type : NECP_TLV_POLICY_CONDITION
3254 * len : ...
3255 * value :
3256 * {
3257 * {
3258 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3259 * len : ...
3260 * value : ...
3261 * }
3262 * {
3263 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3264 * len : ...
3265 * value : ...
3266 * }
3267 * ...
3268 * }
3269 * }
3270 * }
3271 * }
3272 * {
3273 * type : NECP_TLV_POLICY_DUMP
3274 * length : ...
3275 * value :
3276 * {
3277 * {
3278 * type : NECP_TLV_POLICY_ID
3279 * len : ...
3280 * value : ...
3281 * }
3282 * {
3283 * type : NECP_TLV_POLICY_ORDER
3284 * len : ...
3285 * value : ...
3286 * }
3287 * {
3288 * type : NECP_TLV_POLICY_RESULT_STRING
3289 * len : ...
3290 * value : ...
3291 * }
3292 * {
3293 * type : NECP_TLV_POLICY_OWNER
3294 * len : ...
3295 * value : ...
3296 * }
3297 * {
3298 * type : NECP_TLV_POLICY_CONDITION
3299 * len : ...
3300 * value :
3301 * {
3302 * {
3303 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3304 * len : ...
3305 * value : ...
3306 * }
3307 * {
3308 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3309 * len : ...
3310 * value : ...
3311 * }
3312 * ...
3313 * }
3314 * }
3315 * }
3316 * }
3317 * ...
3318 */
3319 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3320 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3321 {
3322 struct necp_kernel_socket_policy * __single policy = NULL;
3323 int policy_i;
3324 int policy_count = 0;
3325 u_int8_t * __indexable * __indexable tlv_buffer_pointers = NULL;
3326 u_int32_t * __indexable tlv_buffer_lengths = NULL;
3327 u_int32_t total_tlv_len = 0;
3328 u_int8_t * __indexable result_buf = NULL;
3329 u_int8_t *result_buf_cursor = result_buf;
3330 char result_string[MAX_RESULT_STRING_LEN];
3331 char proc_name_string[MAXCOMLEN + 1];
3332
3333 int error_code = 0;
3334 bool error_occured = false;
3335 u_int32_t response_error = NECP_ERROR_INTERNAL;
3336
3337 #define REPORT_ERROR(error) error_occured = true; \
3338 response_error = error; \
3339 goto done
3340
3341 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
3342 REPORT_ERROR(error)
3343
3344 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3345 if (cred_result != 0) {
3346 NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3347 REPORT_ERROR(NECP_ERROR_INTERNAL);
3348 }
3349
3350 // LOCK
3351 lck_rw_lock_shared(&necp_kernel_policy_lock);
3352
3353 if (necp_debug) {
3354 NECPLOG0(LOG_DEBUG, "Gathering policies");
3355 }
3356
3357 policy_count = necp_kernel_application_policies_count;
3358
3359 tlv_buffer_pointers = kalloc_type(u_int8_t * __indexable, policy_count, M_WAITOK | Z_ZERO);
3360 if (tlv_buffer_pointers == NULL) {
3361 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3362 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3363 }
3364
3365 tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3366 if (tlv_buffer_lengths == NULL) {
3367 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3368 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3369 }
3370
3371 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3372 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3373
3374 memset(result_string, 0, MAX_RESULT_STRING_LEN);
3375 memset(proc_name_string, 0, MAXCOMLEN + 1);
3376
3377 necp_get_result_description(result_string, policy->result, policy->result_parameter);
3378 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3379
3380 u_int16_t proc_name_len = strbuflen(proc_name_string, sizeof(proc_name_string) - 1) + 1;
3381 u_int16_t result_string_len = strbuflen(result_string, sizeof(result_string) - 1) + 1;
3382
3383 if (necp_debug) {
3384 NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3385 }
3386
3387 u_int32_t total_allocated_bytes = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) + // NECP_TLV_POLICY_ID
3388 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) + // NECP_TLV_POLICY_ORDER
3389 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) + // NECP_TLV_POLICY_SESSION_ORDER
3390 sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len + // NECP_TLV_POLICY_RESULT_STRING
3391 sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len + // NECP_TLV_POLICY_OWNER
3392 sizeof(u_int8_t) + sizeof(u_int32_t); // NECP_TLV_POLICY_CONDITION
3393
3394 // We now traverse the condition_mask to see how much space we need to allocate
3395 u_int64_t condition_mask = policy->condition_mask;
3396 u_int64_t condition_negated_mask = policy->condition_negated_mask;
3397 u_int8_t num_conditions = 0;
3398 struct necp_string_id_mapping *account_id_entry = NULL;
3399 char if_name[IFXNAMSIZ];
3400 u_int32_t condition_tlv_length = 0;
3401 memset(if_name, 0, sizeof(if_name));
3402
3403 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3404 num_conditions++;
3405 } else {
3406 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3407 num_conditions++;
3408 }
3409 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3410 num_conditions++;
3411 }
3412 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3413 snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3414 condition_tlv_length += strbuflen(if_name, sizeof(if_name) - 1) + 1;
3415 num_conditions++;
3416 }
3417 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3418 condition_tlv_length += sizeof(policy->cond_protocol);
3419 num_conditions++;
3420 }
3421 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3422 condition_tlv_length += sizeof(uuid_t);
3423 num_conditions++;
3424 }
3425 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3426 condition_tlv_length += sizeof(uuid_t);
3427 num_conditions++;
3428 }
3429 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3430 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3431 u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3432 condition_tlv_length += domain_len;
3433 num_conditions++;
3434 }
3435 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3436 condition_tlv_length += sizeof(u_int32_t);
3437 num_conditions++;
3438 }
3439 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3440 u_int32_t url_len = strlen(policy->cond_url) + 1;
3441 condition_tlv_length += url_len;
3442 num_conditions++;
3443 }
3444 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3445 account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3446 u_int32_t account_id_len = 0;
3447 if (account_id_entry) {
3448 account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3449 }
3450 condition_tlv_length += account_id_len;
3451 num_conditions++;
3452 }
3453 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3454 condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3455 num_conditions++;
3456 }
3457 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3458 condition_tlv_length += sizeof(uid_t);
3459 num_conditions++;
3460 }
3461 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3462 condition_tlv_length += sizeof(uid_t);
3463 num_conditions++;
3464 }
3465 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3466 condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3467 num_conditions++;
3468 }
3469 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3470 num_conditions++;
3471 }
3472 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3473 u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3474 condition_tlv_length += entitlement_len;
3475 num_conditions++;
3476 }
3477 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3478 num_conditions++;
3479 }
3480 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3481 num_conditions++;
3482 }
3483 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3484 condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3485 num_conditions++;
3486 }
3487 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3488 condition_tlv_length += sizeof(policy->cond_local_networks_flags);
3489 num_conditions++;
3490 }
3491 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3492 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3493 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3494 } else {
3495 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3496 }
3497 num_conditions++;
3498 }
3499 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3500 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3501 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3502 } else {
3503 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3504 }
3505 num_conditions++;
3506 }
3507 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3508 condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3509 num_conditions++;
3510 }
3511 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3512 condition_tlv_length += sizeof(u_int32_t);
3513 num_conditions++;
3514 }
3515 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3516 num_conditions++;
3517 }
3518 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3519 num_conditions++;
3520 }
3521 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3522 u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3523 condition_tlv_length += identifier_len;
3524 num_conditions++;
3525 }
3526 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3527 condition_tlv_length += sizeof(u_int16_t);
3528 num_conditions++;
3529 }
3530 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3531 num_conditions++;
3532 }
3533 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3534 num_conditions++;
3535 }
3536 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3537 condition_tlv_length += sizeof(u_int16_t);
3538 num_conditions++;
3539 }
3540 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3541 condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3542 num_conditions++;
3543 }
3544 }
3545
3546 // These are for the condition TLVs (id, length, flags). The space for "value" is already accounted for above.
3547 condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int8_t));
3548 total_allocated_bytes += condition_tlv_length;
3549
3550 u_int8_t * __indexable tlv_buffer;
3551 tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3552 if (tlv_buffer == NULL) {
3553 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3554 continue;
3555 }
3556
3557 u_int8_t *cursor = tlv_buffer;
3558 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3559 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3560 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3561 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3562 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3563
3564 #define N_QUICK 256
3565 u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3566
3567 u_int8_t * __indexable cond_buf; // To be used for condition TLVs
3568 if (condition_tlv_length <= N_QUICK) {
3569 cond_buf = q_cond_buf;
3570 } else {
3571 cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3572 if (cond_buf == NULL) {
3573 NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3574 kfree_data(tlv_buffer, total_allocated_bytes);
3575 continue;
3576 }
3577 }
3578
3579 memset(cond_buf, 0, condition_tlv_length);
3580 u_int8_t *cond_buf_cursor = cond_buf;
3581 u_int8_t cond_flags = 0;
3582 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3583 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3584 } else {
3585 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3586 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3587 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);
3588 }
3589 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3590 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3591 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);
3592 }
3593 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3594 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3595 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);
3596 }
3597 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3598 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3599 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,
3600 if_name, cond_buf, condition_tlv_length);
3601 }
3602 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3603 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3604 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,
3605 cond_buf, condition_tlv_length);
3606 }
3607 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3608 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3609 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3610 if (entry != NULL) {
3611 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3612 cond_buf, condition_tlv_length);
3613 }
3614 }
3615 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3616 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3617 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3618 if (entry != NULL) {
3619 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3620 cond_buf, condition_tlv_length);
3621 }
3622 }
3623 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3624 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3625 cond_flags = ((condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) || (condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3626 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);
3627 }
3628 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3629 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3630 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,
3631 cond_buf, condition_tlv_length);
3632 }
3633 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3634 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_URL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3635 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);
3636 }
3637 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3638 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3639 if (account_id_entry != NULL) {
3640 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);
3641 }
3642 }
3643 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3644 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3645 uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3646 memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3647 memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3648 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PID, cond_flags, sizeof(pid_buffer), &pid_buffer,
3649 cond_buf, condition_tlv_length);
3650 }
3651 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3652 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3653 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,
3654 cond_buf, condition_tlv_length);
3655 }
3656 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3657 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3658 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,
3659 cond_buf, condition_tlv_length);
3660 }
3661 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3662 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3663 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,
3664 cond_buf, condition_tlv_length);
3665 }
3666 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3667 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3668 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, 0, "",
3669 cond_buf, condition_tlv_length);
3670 }
3671 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3672 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3673 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);
3674 }
3675 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3676 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3677 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);
3678 }
3679 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3680 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3681 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);
3682 }
3683 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3684 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SDK_VERSION) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3685 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION, cond_flags,
3686 sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3687 cond_buf, condition_tlv_length);
3688 }
3689 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3690 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3691 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3692 struct necp_policy_condition_addr_range range;
3693 memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3694 memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3695 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, cond_flags, sizeof(range), &range,
3696 cond_buf, condition_tlv_length);
3697 } else {
3698 struct necp_policy_condition_addr addr;
3699 addr.prefix = policy->cond_local_prefix;
3700 memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3701 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, cond_flags, sizeof(addr), &addr,
3702 cond_buf, condition_tlv_length);
3703 }
3704 }
3705 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3706 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3707 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3708 struct necp_policy_condition_addr_range range;
3709 memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3710 memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3711 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, cond_flags, sizeof(range), &range,
3712 cond_buf, condition_tlv_length);
3713 } else {
3714 struct necp_policy_condition_addr addr;
3715 addr.prefix = policy->cond_remote_prefix;
3716 memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3717 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, cond_flags, sizeof(addr), &addr,
3718 cond_buf, condition_tlv_length);
3719 }
3720 }
3721 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3722 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3723 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE, cond_flags,
3724 sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3725 cond_buf, condition_tlv_length);
3726 }
3727 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3728 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3729 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);
3730 }
3731 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3732 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3733 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);
3734 }
3735 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3736 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3737 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);
3738 }
3739 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3740 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3741 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);
3742 }
3743 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3744 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3745 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);
3746 }
3747 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3748 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3749 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);
3750 }
3751 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3752 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3753 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);
3754 }
3755 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3756 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3757 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);
3758 }
3759 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3760 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3761 uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3762 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3763 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3764 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3765 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, cond_flags, sizeof(flags), &flags,
3766 cond_buf, condition_tlv_length);
3767 }
3768 }
3769
3770 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3771 if (cond_buf != q_cond_buf) {
3772 kfree_data(cond_buf, condition_tlv_length);
3773 }
3774
3775 tlv_buffer_pointers[policy_i] = tlv_buffer;
3776 tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3777
3778 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
3779 total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3780 }
3781
3782 // UNLOCK
3783 lck_rw_done(&necp_kernel_policy_lock);
3784
3785 // Copy out
3786 if (out_buffer != 0) {
3787 if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3788 NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3789 REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3790 }
3791
3792 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3793 result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3794 if (result_buf == NULL) {
3795 NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3796 REPORT_ERROR(NECP_ERROR_INTERNAL);
3797 }
3798
3799 // Add four bytes for total length at the start
3800 memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3801
3802 // Copy the TLVs
3803 result_buf_cursor = result_buf + sizeof(u_int32_t);
3804 for (int i = 0; i < policy_count; i++) {
3805 if (tlv_buffer_pointers[i] != NULL) {
3806 result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3807 result_buf, total_tlv_len + sizeof(u_int32_t));
3808 }
3809 }
3810
3811 int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3812 if (copy_error) {
3813 NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3814 REPORT_ERROR(NECP_ERROR_INTERNAL);
3815 }
3816 }
3817
3818 done:
3819
3820 if (error_occured) {
3821 error_code = necp_get_posix_error_for_necp_error(response_error);
3822 }
3823
3824 if (result_buf != NULL) {
3825 kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3826 }
3827
3828 if (tlv_buffer_pointers != NULL) {
3829 for (int i = 0; i < policy_count; i++) {
3830 if (tlv_buffer_pointers[i] != NULL) {
3831 kfree_data_addr(tlv_buffer_pointers[i]);
3832 tlv_buffer_pointers[i] = NULL;
3833 }
3834 }
3835 kfree_type(u_int8_t * __indexable, policy_count, tlv_buffer_pointers);
3836 }
3837
3838 if (tlv_buffer_lengths != NULL) {
3839 kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3840 }
3841 #undef N_QUICK
3842 #undef RESET_COND_BUF
3843 #undef REPORT_ERROR
3844 #undef UNLOCK_AND_REPORT_ERROR
3845
3846 return error_code;
3847 }
3848
3849 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)3850 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)
3851 {
3852 struct necp_session_policy *new_policy = NULL;
3853 struct necp_session_policy *tmp_policy = NULL;
3854
3855 if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3856 goto done;
3857 }
3858
3859 new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3860 new_policy->applied = FALSE;
3861 new_policy->pending_deletion = FALSE;
3862 new_policy->pending_update = FALSE;
3863 new_policy->order = order;
3864 new_policy->conditions = conditions_array;
3865 new_policy->conditions_size = conditions_array_size;
3866 new_policy->route_rules = route_rules_array;
3867 new_policy->route_rules_size = route_rules_array_size;
3868 new_policy->result = result;
3869 new_policy->result_size = result_size;
3870 new_policy->local_id = necp_policy_get_new_id(session);
3871
3872 LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3873
3874 session->dirty = TRUE;
3875
3876 if (necp_debug) {
3877 NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3878 }
3879 done:
3880 return new_policy;
3881 }
3882
3883 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3884 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3885 {
3886 struct necp_session_policy *policy = NULL;
3887 if (policy_id == 0) {
3888 return NULL;
3889 }
3890
3891 LIST_FOREACH(policy, &session->policies, chain) {
3892 if (policy->local_id == policy_id) {
3893 return policy;
3894 }
3895 }
3896
3897 return NULL;
3898 }
3899
3900 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3901 necp_policy_get_result_type(struct necp_session_policy *policy)
3902 {
3903 return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3904 }
3905
3906 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3907 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3908 {
3909 return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3910 }
3911
3912 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)3913 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)
3914 {
3915 if (policy) {
3916 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3917 if (parameter_buffer_length >= parameter_length) {
3918 u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3919 if (parameter && parameter_buffer) {
3920 memcpy(parameter_buffer, parameter, parameter_length);
3921 return TRUE;
3922 }
3923 }
3924 }
3925
3926 return FALSE;
3927 }
3928
3929 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)3930 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
3931 {
3932 if (session == NULL || policy == NULL) {
3933 return FALSE;
3934 }
3935
3936 policy->pending_deletion = TRUE;
3937 session->dirty = TRUE;
3938
3939 if (necp_debug) {
3940 NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
3941 }
3942 return TRUE;
3943 }
3944
3945 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)3946 necp_policy_mark_all_for_deletion(struct necp_session *session)
3947 {
3948 struct necp_session_policy *policy = NULL;
3949 struct necp_session_policy *temp_policy = NULL;
3950
3951 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
3952 necp_policy_mark_for_deletion(session, policy);
3953 }
3954
3955 return TRUE;
3956 }
3957
3958 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)3959 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
3960 {
3961 if (session == NULL || policy == NULL) {
3962 return FALSE;
3963 }
3964
3965 LIST_REMOVE(policy, chain);
3966
3967 if (policy->result) {
3968 kfree_data_sized_by(policy->result, policy->result_size);
3969 policy->result = NULL;
3970 policy->result_size = 0;
3971 }
3972
3973 if (policy->conditions) {
3974 kfree_data_sized_by(policy->conditions, policy->conditions_size);
3975 policy->conditions = NULL;
3976 policy->conditions_size = 0;
3977 }
3978
3979 if (policy->route_rules) {
3980 kfree_data_sized_by(policy->route_rules, policy->route_rules_size);
3981 policy->route_rules = NULL;
3982 policy->route_rules_size = 0;
3983 }
3984
3985 zfree(necp_session_policy_zone, policy);
3986
3987 if (necp_debug) {
3988 NECPLOG0(LOG_DEBUG, "Removed NECP policy");
3989 }
3990 return TRUE;
3991 }
3992
3993 static bool
necp_policy_unapply(struct necp_session_policy * policy)3994 necp_policy_unapply(struct necp_session_policy *policy)
3995 {
3996 int i = 0;
3997 if (policy == NULL) {
3998 return FALSE;
3999 }
4000
4001 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4002
4003 // Release local uuid mappings
4004 if (!uuid_is_null(policy->applied_app_uuid)) {
4005 bool removed_mapping = FALSE;
4006 if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
4007 necp_uuid_app_id_mappings_dirty = TRUE;
4008 necp_num_uuid_app_id_mappings--;
4009 }
4010 uuid_clear(policy->applied_app_uuid);
4011 }
4012 if (!uuid_is_null(policy->applied_real_app_uuid)) {
4013 necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
4014 uuid_clear(policy->applied_real_app_uuid);
4015 }
4016 if (!uuid_is_null(policy->applied_result_uuid)) {
4017 necp_remove_agent_uuid_id_mapping(policy->applied_result_uuid);
4018 uuid_clear(policy->applied_result_uuid);
4019 }
4020
4021 // Release string mappings
4022 if (policy->applied_account != NULL) {
4023 necp_remove_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(policy->applied_account));
4024 kfree_data_sized_by(policy->applied_account, policy->applied_account_size);
4025 policy->applied_account = NULL;
4026 policy->applied_account_size = 0;
4027 }
4028
4029 // Release route rule
4030 if (policy->applied_route_rules_id != 0) {
4031 necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
4032 policy->applied_route_rules_id = 0;
4033 }
4034
4035 // Release agent type mapping
4036 if (policy->applied_agent_type_id != 0) {
4037 necp_remove_agent_type_to_id_mapping(policy->applied_agent_type_id);
4038 policy->applied_agent_type_id = 0;
4039 }
4040
4041 // Remove socket policies
4042 for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
4043 if (policy->kernel_socket_policies[i] != 0) {
4044 necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
4045 policy->kernel_socket_policies[i] = 0;
4046 }
4047 }
4048
4049 // Remove IP output policies
4050 for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
4051 if (policy->kernel_ip_output_policies[i] != 0) {
4052 necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
4053 policy->kernel_ip_output_policies[i] = 0;
4054 }
4055 }
4056
4057 policy->applied = FALSE;
4058
4059 return TRUE;
4060 }
4061
4062 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
4063 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
4064 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
4065 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
4066 struct necp_policy_result_ip_tunnel {
4067 u_int32_t secondary_result;
4068 char interface_name[IFXNAMSIZ];
4069 } __attribute__((__packed__));
4070
4071 struct necp_policy_result_service {
4072 uuid_t identifier;
4073 u_int32_t data;
4074 } __attribute__((__packed__));
4075
4076 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy,bool * should_update_immediately)4077 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy, bool *should_update_immediately)
4078 {
4079 bool socket_only_conditions = FALSE;
4080 bool socket_ip_conditions = FALSE;
4081
4082 bool socket_layer_non_id_conditions = FALSE;
4083 bool ip_output_layer_non_id_conditions = FALSE;
4084 bool ip_output_layer_non_id_only = FALSE;
4085 bool ip_output_layer_id_condition = FALSE;
4086 bool ip_output_layer_tunnel_condition_from_id = FALSE;
4087 bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
4088 necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
4089
4090 u_int64_t master_condition_mask = 0;
4091 u_int64_t master_condition_negated_mask = 0;
4092 ifnet_t __single cond_bound_interface = NULL;
4093 u_int32_t cond_account_id = 0;
4094 char *cond_domain __null_terminated = NULL;
4095 u_int32_t cond_domain_filter = 0;
4096 char *cond_url __null_terminated = NULL;
4097 char *cond_custom_entitlement __null_terminated = NULL;
4098 char *cond_signing_identifier __null_terminated = NULL;
4099 pid_t cond_pid = 0;
4100 int32_t cond_pid_version = 0;
4101 uid_t cond_uid = 0;
4102 uid_t cond_real_uid = 0;
4103 necp_app_id cond_app_id = 0;
4104 necp_app_id cond_real_app_id = 0;
4105 struct necp_policy_condition_tc_range cond_traffic_class;
4106 cond_traffic_class.start_tc = 0;
4107 cond_traffic_class.end_tc = 0;
4108 u_int16_t cond_protocol = 0;
4109 union necp_sockaddr_union cond_local_start;
4110 union necp_sockaddr_union cond_local_end;
4111 u_int8_t cond_local_prefix = 0;
4112 union necp_sockaddr_union cond_remote_start;
4113 union necp_sockaddr_union cond_remote_end;
4114 u_int8_t cond_remote_prefix = 0;
4115 u_int32_t cond_client_flags = 0;
4116 u_int8_t cond_local_networks_flags = 0;
4117 u_int32_t offset = 0;
4118 u_int8_t ultimate_result = 0;
4119 u_int32_t secondary_result = 0;
4120 struct necp_policy_condition_agent_type cond_agent_type = {};
4121 struct necp_policy_condition_sdk_version cond_sdk_version = {};
4122 u_int16_t cond_packet_filter_tags = 0;
4123 u_int16_t cond_scheme_port = 0;
4124 u_int32_t cond_bound_interface_flags = 0;
4125 u_int32_t cond_bound_interface_eflags = 0;
4126 u_int32_t cond_bound_interface_xflags = 0;
4127 necp_kernel_policy_result_parameter secondary_result_parameter;
4128 memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
4129 u_int32_t cond_last_interface_index = 0;
4130 necp_kernel_policy_result_parameter ultimate_result_parameter;
4131 memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
4132
4133 if (policy == NULL) {
4134 return FALSE;
4135 }
4136
4137 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4138
4139 // Process conditions
4140 while (offset < policy->conditions_size) {
4141 u_int32_t length = 0;
4142 u_int8_t * __indexable value = necp_buffer_get_tlv_value(policy->conditions, policy->conditions_size, offset, &length);
4143
4144 u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
4145 u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
4146 bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
4147 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
4148 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
4149 switch (condition_type) {
4150 case NECP_POLICY_CONDITION_DEFAULT: {
4151 socket_ip_conditions = TRUE;
4152 break;
4153 }
4154 case NECP_POLICY_CONDITION_ALL_INTERFACES: {
4155 master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
4156 socket_ip_conditions = TRUE;
4157 break;
4158 }
4159 case NECP_POLICY_CONDITION_HAS_CLIENT: {
4160 master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
4161 socket_only_conditions = TRUE;
4162 break;
4163 }
4164 case NECP_POLICY_CONDITION_ENTITLEMENT: {
4165 if (condition_length > 0) {
4166 if (cond_custom_entitlement == NULL) {
4167 cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
4168 if (cond_custom_entitlement != NULL) {
4169 master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
4170 socket_only_conditions = TRUE;
4171 }
4172 }
4173 } else {
4174 master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
4175 socket_only_conditions = TRUE;
4176 }
4177 break;
4178 }
4179 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
4180 master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4181 if (condition_is_negative) {
4182 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4183 }
4184 socket_only_conditions = TRUE;
4185 break;
4186 }
4187 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
4188 master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
4189 socket_only_conditions = TRUE;
4190 break;
4191 }
4192 case NECP_POLICY_CONDITION_SDK_VERSION: {
4193 if (condition_length >= sizeof(cond_sdk_version)) {
4194 master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
4195 memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
4196 socket_only_conditions = TRUE;
4197 }
4198 break;
4199 }
4200 case NECP_POLICY_CONDITION_DOMAIN: {
4201 // Make sure there is only one such rule
4202 if (condition_length > 0 && cond_domain == NULL) {
4203 const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
4204
4205 u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
4206 cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
4207 if (cond_domain != NULL) {
4208 master_condition_mask |= mask_value;
4209 if (condition_is_negative) {
4210 master_condition_negated_mask |= mask_value;
4211 }
4212 socket_only_conditions = TRUE;
4213 }
4214 }
4215 break;
4216 }
4217 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
4218 // Make sure there is only one such rule
4219 if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
4220 memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
4221 if (cond_domain_filter != 0) {
4222 master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4223 if (condition_is_negative) {
4224 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4225 }
4226 socket_only_conditions = TRUE;
4227 }
4228 }
4229 break;
4230 }
4231 case NECP_POLICY_CONDITION_URL: {
4232 // Make sure there is only one such rule
4233 if (condition_length > 0 && cond_url == NULL) {
4234 u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
4235 cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
4236 if (cond_url != NULL) {
4237 master_condition_mask |= mask_value;
4238 if (condition_is_negative) {
4239 master_condition_negated_mask |= mask_value;
4240 }
4241 socket_only_conditions = TRUE;
4242 }
4243 }
4244 break;
4245 }
4246 case NECP_POLICY_CONDITION_ACCOUNT: {
4247 // Make sure there is only one such rule
4248 if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
4249 size_t string_buffer_size = 0;
4250 char * __sized_by(string_buffer_size) string = NULL;
4251 string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
4252 string_buffer_size = condition_length + 1;
4253 if (string != NULL) {
4254 memcpy(string, condition_value, condition_length);
4255 string[condition_length] = 0;
4256 cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(string, &string[condition_length]));
4257 if (cond_account_id != 0) {
4258 policy->applied_account = string; // Save the string in parent policy
4259 policy->applied_account_size = string_buffer_size;
4260 master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4261 if (condition_is_negative) {
4262 master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4263 }
4264 socket_only_conditions = TRUE;
4265 } else {
4266 kfree_data_sized_by(string, string_buffer_size);
4267 }
4268 }
4269 }
4270 break;
4271 }
4272 case NECP_POLICY_CONDITION_APPLICATION: {
4273 // Make sure there is only one such rule, because we save the uuid in the policy
4274 if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
4275 bool allocated_mapping = FALSE;
4276 uuid_t application_uuid;
4277 memcpy(application_uuid, condition_value, sizeof(uuid_t));
4278 cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
4279 if (cond_app_id != 0) {
4280 if (allocated_mapping) {
4281 necp_uuid_app_id_mappings_dirty = TRUE;
4282 necp_num_uuid_app_id_mappings++;
4283 }
4284 uuid_copy(policy->applied_app_uuid, application_uuid);
4285 master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
4286 if (condition_is_negative) {
4287 master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
4288 }
4289 socket_only_conditions = TRUE;
4290 }
4291 }
4292 break;
4293 }
4294 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
4295 // Make sure there is only one such rule, because we save the uuid in the policy
4296 if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
4297 uuid_t real_application_uuid;
4298 memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
4299 cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
4300 if (cond_real_app_id != 0) {
4301 uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
4302 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4303 if (condition_is_negative) {
4304 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4305 }
4306 socket_only_conditions = TRUE;
4307 }
4308 }
4309 break;
4310 }
4311 case NECP_POLICY_CONDITION_PID: {
4312 if (condition_length >= sizeof(pid_t)) {
4313 master_condition_mask |= NECP_KERNEL_CONDITION_PID;
4314 if (condition_is_negative) {
4315 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
4316 }
4317 memcpy(&cond_pid, condition_value, sizeof(cond_pid));
4318 if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
4319 memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
4320 }
4321 socket_only_conditions = TRUE;
4322 }
4323 break;
4324 }
4325 case NECP_POLICY_CONDITION_UID: {
4326 if (condition_length >= sizeof(uid_t)) {
4327 master_condition_mask |= NECP_KERNEL_CONDITION_UID;
4328 if (condition_is_negative) {
4329 master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
4330 }
4331 memcpy(&cond_uid, condition_value, sizeof(cond_uid));
4332 socket_only_conditions = TRUE;
4333 }
4334 break;
4335 }
4336 case NECP_POLICY_CONDITION_REAL_UID: {
4337 if (condition_length >= sizeof(uid_t)) {
4338 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4339 if (condition_is_negative) {
4340 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4341 }
4342 memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
4343 socket_only_conditions = TRUE;
4344 }
4345 break;
4346 }
4347 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
4348 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
4349 master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4350 if (condition_is_negative) {
4351 master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4352 }
4353 memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
4354 socket_only_conditions = TRUE;
4355 }
4356 break;
4357 }
4358 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4359 if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4360 char interface_name[IFXNAMSIZ];
4361 memcpy(interface_name, condition_value, condition_length);
4362 interface_name[condition_length - 1] = 0; // Make sure the string is NULL terminated
4363 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[condition_length - 1]), &cond_bound_interface) == 0) {
4364 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4365 if (condition_is_negative) {
4366 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4367 }
4368 }
4369 socket_ip_conditions = TRUE;
4370 }
4371 break;
4372 }
4373 case NECP_POLICY_CONDITION_IP_PROTOCOL:
4374 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4375 if (condition_length >= sizeof(u_int16_t)) {
4376 master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4377 if (condition_is_negative) {
4378 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4379 }
4380 memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4381 if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4382 socket_only_conditions = TRUE;
4383 } else {
4384 socket_ip_conditions = TRUE;
4385 }
4386 }
4387 break;
4388 }
4389 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4390 if (condition_is_negative) {
4391 master_condition_negated_mask |= NECP_POLICY_CONDITION_LOCAL_NETWORKS;
4392 }
4393 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4394 socket_ip_conditions = TRUE;
4395 if (condition_length >= sizeof(u_int8_t)) {
4396 memcpy(&cond_local_networks_flags, condition_value, sizeof(cond_local_networks_flags));
4397 }
4398 break;
4399 }
4400 case NECP_POLICY_CONDITION_LOCAL_ADDR:
4401 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4402 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4403 if (!necp_address_is_valid(&address_struct->address.sa)) {
4404 break;
4405 }
4406
4407 cond_local_prefix = address_struct->prefix;
4408 memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4409 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4410 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4411 if (condition_is_negative) {
4412 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4413 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4414 }
4415 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4416 socket_only_conditions = TRUE;
4417 } else {
4418 socket_ip_conditions = TRUE;
4419 }
4420 break;
4421 }
4422 case NECP_POLICY_CONDITION_REMOTE_ADDR:
4423 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4424 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4425 if (!necp_address_is_valid(&address_struct->address.sa)) {
4426 break;
4427 }
4428
4429 cond_remote_prefix = address_struct->prefix;
4430 memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4431 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4432 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4433 if (condition_is_negative) {
4434 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4435 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4436 }
4437 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4438 socket_only_conditions = TRUE;
4439 } else {
4440 socket_ip_conditions = TRUE;
4441 }
4442 break;
4443 }
4444 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4445 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4446 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4447 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4448 !necp_address_is_valid(&address_struct->end_address.sa)) {
4449 break;
4450 }
4451
4452 memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4453 memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4454 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4455 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4456 if (condition_is_negative) {
4457 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4458 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4459 }
4460 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4461 socket_only_conditions = TRUE;
4462 } else {
4463 socket_ip_conditions = TRUE;
4464 }
4465 break;
4466 }
4467 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4468 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4469 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4470 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4471 !necp_address_is_valid(&address_struct->end_address.sa)) {
4472 break;
4473 }
4474
4475 memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4476 memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4477 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4478 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4479 if (condition_is_negative) {
4480 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4481 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4482 }
4483 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4484 socket_only_conditions = TRUE;
4485 } else {
4486 socket_ip_conditions = TRUE;
4487 }
4488 break;
4489 }
4490 case NECP_POLICY_CONDITION_AGENT_TYPE: {
4491 if (condition_length >= sizeof(cond_agent_type)) {
4492 master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4493 memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4494 socket_only_conditions = TRUE;
4495 }
4496 break;
4497 }
4498 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4499 if (condition_is_negative) {
4500 master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4501 }
4502 master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4503 socket_only_conditions = TRUE;
4504 if (condition_length >= sizeof(u_int32_t)) {
4505 memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4506 } else {
4507 // Empty means match on fallback traffic
4508 cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4509 }
4510 break;
4511 }
4512 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4513 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4514 if (condition_is_negative) {
4515 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4516 }
4517 socket_only_conditions = TRUE;
4518 break;
4519 }
4520 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4521 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4522 if (condition_is_negative) {
4523 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4524 }
4525 socket_only_conditions = TRUE;
4526 break;
4527 }
4528 case NECP_POLICY_CONDITION_SCHEME_PORT: {
4529 master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4530 if (condition_is_negative) {
4531 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4532 }
4533 memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4534 socket_ip_conditions = TRUE;
4535 break;
4536 }
4537 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4538 if (condition_length > 0) {
4539 if (cond_signing_identifier == NULL) {
4540 cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4541 if (cond_signing_identifier != NULL) {
4542 master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4543 socket_only_conditions = TRUE;
4544 if (condition_is_negative) {
4545 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4546 }
4547 }
4548 }
4549 }
4550 break;
4551 }
4552 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4553 if (condition_length >= sizeof(u_int16_t)) {
4554 master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4555 if (condition_is_negative) {
4556 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4557 }
4558 memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4559 socket_ip_conditions = TRUE;
4560 }
4561 break;
4562 }
4563 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4564 master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4565 if (condition_is_negative) {
4566 master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4567 }
4568 socket_only_conditions = TRUE;
4569 break;
4570 }
4571 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4572 master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4573 if (condition_is_negative) {
4574 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4575 }
4576 socket_only_conditions = TRUE;
4577 break;
4578 }
4579 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4580 if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4581 u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4582 memcpy(&flags, condition_value, sizeof(flags));
4583 cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4584 cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4585 cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4586 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4587 if (condition_is_negative) {
4588 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4589 }
4590 socket_ip_conditions = TRUE;
4591 }
4592 break;
4593 }
4594 default: {
4595 break;
4596 }
4597 }
4598
4599 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4600 }
4601
4602 // Process result
4603 ultimate_result = necp_policy_get_result_type(policy);
4604 switch (ultimate_result) {
4605 case NECP_POLICY_RESULT_PASS: {
4606 u_int32_t pass_flags = 0;
4607 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4608 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4609 ultimate_result_parameter.pass_flags = pass_flags;
4610 }
4611 }
4612 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4613 socket_layer_non_id_conditions = TRUE;
4614 ip_output_layer_id_condition = TRUE;
4615 } else if (socket_ip_conditions) {
4616 socket_layer_non_id_conditions = TRUE;
4617 ip_output_layer_id_condition = TRUE;
4618 ip_output_layer_non_id_conditions = TRUE;
4619 }
4620 break;
4621 }
4622 case NECP_POLICY_RESULT_DROP: {
4623 u_int32_t drop_flags = 0;
4624 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4625 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4626 ultimate_result_parameter.drop_flags = drop_flags;
4627 if (ultimate_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_DEFUNCT_ALL_FLOWS) {
4628 if (should_update_immediately != NULL) {
4629 *should_update_immediately = TRUE;
4630 }
4631 }
4632 }
4633 }
4634 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4635 socket_layer_non_id_conditions = TRUE;
4636 } else if (socket_ip_conditions) {
4637 socket_layer_non_id_conditions = TRUE;
4638 ip_output_layer_non_id_conditions = TRUE;
4639 ip_output_layer_non_id_only = TRUE; // Only apply drop to packets that didn't go through socket layer
4640 }
4641 break;
4642 }
4643 case NECP_POLICY_RESULT_SKIP: {
4644 u_int32_t skip_policy_order = 0;
4645 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4646 ultimate_result_parameter.skip_policy_order = skip_policy_order;
4647 }
4648
4649 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4650 socket_layer_non_id_conditions = TRUE;
4651 ip_output_layer_id_condition = TRUE;
4652 } else if (socket_ip_conditions) {
4653 socket_layer_non_id_conditions = TRUE;
4654 ip_output_layer_non_id_conditions = TRUE;
4655 }
4656 break;
4657 }
4658 case NECP_POLICY_RESULT_SOCKET_DIVERT:
4659 case NECP_POLICY_RESULT_SOCKET_FILTER: {
4660 u_int32_t control_unit = 0;
4661 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4662 ultimate_result_parameter.flow_divert_control_unit = control_unit;
4663 }
4664 socket_layer_non_id_conditions = TRUE;
4665 break;
4666 }
4667 case NECP_POLICY_RESULT_IP_TUNNEL: {
4668 struct necp_policy_result_ip_tunnel tunnel_parameters;
4669 u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4670 if (tunnel_parameters_length > sizeof(u_int32_t) &&
4671 tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4672 necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4673 ifnet_t __single tunnel_interface = NULL;
4674 tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0; // Make sure the string is NULL terminated
4675 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4676 ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4677 ifnet_release(tunnel_interface);
4678 }
4679
4680 secondary_result = tunnel_parameters.secondary_result;
4681 if (secondary_result) {
4682 cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4683 }
4684 }
4685
4686 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4687 socket_layer_non_id_conditions = TRUE;
4688 ip_output_layer_id_condition = TRUE;
4689 if (secondary_result) {
4690 ip_output_layer_tunnel_condition_from_id = TRUE;
4691 }
4692 } else if (socket_ip_conditions) {
4693 socket_layer_non_id_conditions = TRUE;
4694 ip_output_layer_id_condition = TRUE;
4695 ip_output_layer_non_id_conditions = TRUE;
4696 if (secondary_result) {
4697 ip_output_layer_tunnel_condition_from_id = TRUE;
4698 ip_output_layer_tunnel_condition_from_non_id = TRUE;
4699 }
4700 }
4701 break;
4702 }
4703 case NECP_POLICY_RESULT_USE_NETAGENT:
4704 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4705 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4706 uuid_t netagent_uuid;
4707 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4708 ultimate_result_parameter.netagent_id = necp_create_agent_uuid_id_mapping(netagent_uuid);
4709 if (ultimate_result_parameter.netagent_id != 0) {
4710 uuid_copy(policy->applied_result_uuid, netagent_uuid);
4711 socket_layer_non_id_conditions = TRUE;
4712 }
4713 }
4714 break;
4715 }
4716 case NECP_POLICY_RESULT_REMOVE_NETAGENT_TYPE: {
4717 struct necp_policy_condition_agent_type netagent_type = {};
4718 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_type, sizeof(netagent_type))) {
4719 ultimate_result_parameter.netagent_id = necp_create_agent_type_to_id_mapping(&netagent_type);
4720 if (ultimate_result_parameter.netagent_id != 0) {
4721 policy->applied_agent_type_id = ultimate_result_parameter.netagent_id;
4722 socket_layer_non_id_conditions = TRUE;
4723 }
4724 }
4725 break;
4726 }
4727 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4728 u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4729 if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4730 char interface_name[IFXNAMSIZ];
4731 ifnet_t __single scope_interface = NULL;
4732 necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4733 interface_name[interface_name_length - 1] = 0; // Make sure the string is NULL terminated
4734 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4735 ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4736 socket_layer_non_id_conditions = TRUE;
4737 ifnet_release(scope_interface);
4738 }
4739 }
4740 break;
4741 }
4742 case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4743 socket_layer_non_id_conditions = TRUE;
4744 break;
4745 }
4746 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4747 socket_layer_non_id_conditions = TRUE;
4748 break;
4749 }
4750 case NECP_POLICY_RESULT_ROUTE_RULES: {
4751 if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4752 bool has_socket_only_actions = FALSE;
4753 u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4754 if (route_rule_id > 0) {
4755 policy->applied_route_rules_id = route_rule_id;
4756 ultimate_result_parameter.route_rule_id = route_rule_id;
4757 if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4758 socket_layer_non_id_conditions = TRUE;
4759 } else if (socket_ip_conditions) {
4760 socket_layer_non_id_conditions = TRUE;
4761 ip_output_layer_non_id_conditions = TRUE;
4762 ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4763 }
4764 }
4765 }
4766 break;
4767 }
4768 default: {
4769 break;
4770 }
4771 }
4772
4773 if (socket_layer_non_id_conditions) {
4774 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);
4775
4776 if (policy_id == 0) {
4777 NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4778 goto fail;
4779 }
4780
4781 cond_ip_output_layer_id = policy_id;
4782 policy->kernel_socket_policies[0] = policy_id;
4783 }
4784
4785 if (ip_output_layer_non_id_conditions) {
4786 u_int64_t condition_mask = master_condition_mask;
4787 if (ip_output_layer_non_id_only) {
4788 condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4789 }
4790
4791 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);
4792
4793 if (policy_id == 0) {
4794 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4795 goto fail;
4796 }
4797
4798 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4799 }
4800
4801 if (ip_output_layer_id_condition) {
4802 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);
4803
4804 if (policy_id == 0) {
4805 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4806 goto fail;
4807 }
4808
4809 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4810 }
4811
4812 // Extra policies for IP Output tunnels for when packets loop back
4813 if (ip_output_layer_tunnel_condition_from_id) {
4814 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);
4815
4816 if (policy_id == 0) {
4817 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4818 goto fail;
4819 }
4820
4821 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4822 }
4823
4824 if (ip_output_layer_tunnel_condition_from_id) {
4825 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);
4826
4827 if (policy_id == 0) {
4828 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4829 goto fail;
4830 }
4831
4832 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4833 }
4834
4835 policy->applied = TRUE;
4836 policy->pending_update = FALSE;
4837 return TRUE;
4838
4839 fail:
4840 return FALSE;
4841 }
4842
4843 static void
necp_policy_apply_all(struct necp_session * session)4844 necp_policy_apply_all(struct necp_session *session)
4845 {
4846 struct necp_session_policy *policy = NULL;
4847 struct necp_session_policy *temp_policy = NULL;
4848 struct kev_necp_policies_changed_data kev_data;
4849 kev_data.changed_count = 0;
4850 bool should_update_immediately = FALSE;
4851
4852 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4853
4854 // Remove exisiting applied policies
4855 if (session->dirty) {
4856 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4857 if (policy->pending_deletion) {
4858 if (policy->applied) {
4859 necp_policy_unapply(policy);
4860 }
4861 // Delete the policy
4862 necp_policy_delete(session, policy);
4863 } else if (!policy->applied) {
4864 necp_policy_apply(session, policy, &should_update_immediately);
4865 } else if (policy->pending_update) {
4866 // Must have been applied, but needs an update. Remove and re-add.
4867 necp_policy_unapply(policy);
4868 necp_policy_apply(session, policy, &should_update_immediately);
4869 }
4870 }
4871
4872 necp_kernel_socket_policies_update_uuid_table();
4873 necp_kernel_socket_policies_reprocess();
4874 necp_kernel_ip_output_policies_reprocess();
4875
4876 // Clear dirty bit flags
4877 session->dirty = FALSE;
4878 }
4879
4880 lck_rw_done(&necp_kernel_policy_lock);
4881
4882 if (!should_update_immediately) {
4883 necp_update_all_clients();
4884 } else {
4885 necp_update_all_clients_immediately_if_needed(true);
4886 }
4887
4888 necp_post_change_event(&kev_data);
4889
4890 if (necp_debug) {
4891 NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4892 }
4893 }
4894
4895 // Kernel Policy Management
4896 // ---------------------
4897 // Kernel policies are derived from session policies
4898 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4899 necp_kernel_policy_get_new_id(bool socket_level)
4900 {
4901 static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4902 static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4903
4904 necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4905
4906 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4907
4908 if (socket_level) {
4909 bool wrapped = FALSE;
4910 do {
4911 necp_last_kernel_socket_policy_id++;
4912 if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4913 necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4914 if (wrapped) {
4915 // Already wrapped, give up
4916 NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4917 return NECP_KERNEL_POLICY_ID_NONE;
4918 }
4919 necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4920 wrapped = TRUE;
4921 }
4922 newid = necp_last_kernel_socket_policy_id;
4923 } while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4924 } else {
4925 bool wrapped = FALSE;
4926 do {
4927 necp_last_kernel_ip_policy_id++;
4928 if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4929 if (wrapped) {
4930 // Already wrapped, give up
4931 NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4932 return NECP_KERNEL_POLICY_ID_NONE;
4933 }
4934 necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4935 wrapped = TRUE;
4936 }
4937 newid = necp_last_kernel_ip_policy_id;
4938 } while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4939 }
4940
4941 if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4942 NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4943 return NECP_KERNEL_POLICY_ID_NONE;
4944 }
4945
4946 return newid;
4947 }
4948
4949 #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)
4950
4951 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)4952 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)
4953 {
4954 struct necp_kernel_socket_policy *new_kernel_policy = NULL;
4955 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4956
4957 new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
4958
4959 new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
4960 new_kernel_policy->order = order;
4961 new_kernel_policy->session_order = session_order;
4962 new_kernel_policy->session_pid = session_pid;
4963
4964 // Sanitize condition mask
4965 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
4966 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
4967 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4968 }
4969 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
4970 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4971 }
4972 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
4973 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
4974 }
4975 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
4976 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4977 }
4978 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
4979 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4980 }
4981 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
4982 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
4983 }
4984 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
4985 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
4986 }
4987 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
4988
4989 // Set condition values
4990 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4991 new_kernel_policy->cond_app_id = cond_app_id;
4992 }
4993 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4994 new_kernel_policy->cond_real_app_id = cond_real_app_id;
4995 }
4996 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
4997 new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
4998 }
4999 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
5000 new_kernel_policy->cond_account_id = cond_account_id;
5001 }
5002 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
5003 (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
5004 new_kernel_policy->cond_domain = cond_domain;
5005 new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
5006 }
5007 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
5008 new_kernel_policy->cond_domain_filter = cond_domain_filter;
5009 }
5010 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
5011 new_kernel_policy->cond_url = cond_url;
5012 }
5013 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
5014 new_kernel_policy->cond_pid = cond_pid;
5015 new_kernel_policy->cond_pid_version = cond_pid_version;
5016 }
5017 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
5018 new_kernel_policy->cond_uid = cond_uid;
5019 }
5020 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
5021 new_kernel_policy->cond_real_uid = cond_real_uid;
5022 }
5023 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
5024 if (cond_bound_interface) {
5025 ifnet_reference(cond_bound_interface);
5026 }
5027 new_kernel_policy->cond_bound_interface = cond_bound_interface;
5028 }
5029 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
5030 new_kernel_policy->cond_traffic_class = cond_traffic_class;
5031 }
5032 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
5033 new_kernel_policy->cond_protocol = cond_protocol;
5034 }
5035 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5036 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
5037 }
5038 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5039 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
5040 }
5041 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5042 new_kernel_policy->cond_local_prefix = cond_local_prefix;
5043 }
5044 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5045 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
5046 }
5047 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5048 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
5049 }
5050 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5051 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
5052 }
5053 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
5054 memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
5055 }
5056 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
5057 memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
5058 }
5059 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
5060 new_kernel_policy->cond_client_flags = cond_client_flags;
5061 }
5062 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
5063 new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
5064 }
5065 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
5066 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
5067 }
5068 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
5069 new_kernel_policy->cond_scheme_port = cond_scheme_port;
5070 }
5071 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
5072 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
5073 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
5074 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
5075 }
5076 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
5077 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
5078 }
5079
5080 new_kernel_policy->result = result;
5081 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
5082
5083 if (necp_debug) {
5084 NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
5085 }
5086 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
5087
5088 return new_kernel_policy ? new_kernel_policy->id : 0;
5089 }
5090
5091 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)5092 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
5093 {
5094 struct necp_kernel_socket_policy *kernel_policy = NULL;
5095 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5096
5097 if (policy_id == 0) {
5098 return NULL;
5099 }
5100
5101 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
5102 if (kernel_policy->id == policy_id) {
5103 return kernel_policy;
5104 }
5105 }
5106
5107 return NULL;
5108 }
5109
5110 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)5111 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
5112 {
5113 struct necp_kernel_socket_policy * __single policy = NULL;
5114 char * __indexable buffer = NULL;
5115 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5116
5117 policy = necp_kernel_socket_policy_find(policy_id);
5118 if (policy) {
5119 LIST_REMOVE(policy, chain);
5120
5121 if (policy->cond_bound_interface) {
5122 ifnet_release(policy->cond_bound_interface);
5123 policy->cond_bound_interface = NULL;
5124 }
5125
5126 if (policy->cond_domain) {
5127 buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
5128 kfree_data_addr(buffer);
5129 policy->cond_domain = NULL;
5130 }
5131
5132 if (policy->cond_url) {
5133 buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
5134 kfree_data_addr(buffer);
5135 policy->cond_url = NULL;
5136 }
5137
5138 if (policy->cond_custom_entitlement) {
5139 buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
5140 kfree_data_addr(buffer);
5141 policy->cond_custom_entitlement = NULL;
5142 }
5143
5144 if (policy->cond_signing_identifier) {
5145 buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
5146 kfree_data_addr(buffer);
5147 policy->cond_signing_identifier = NULL;
5148 }
5149
5150 zfree(necp_socket_policy_zone, policy);
5151 return TRUE;
5152 }
5153
5154 return FALSE;
5155 }
5156
5157 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)5158 __sized_by(MAX_RESULT_STRING_LEN)
5159 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)
5160 {
5161 uuid_string_t uuid_string;
5162 switch (result) {
5163 case NECP_KERNEL_POLICY_RESULT_NONE: {
5164 snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
5165 break;
5166 }
5167 case NECP_KERNEL_POLICY_RESULT_PASS: {
5168 snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
5169 break;
5170 }
5171 case NECP_KERNEL_POLICY_RESULT_SKIP: {
5172 snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
5173 break;
5174 }
5175 case NECP_KERNEL_POLICY_RESULT_DROP: {
5176 snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5177 break;
5178 }
5179 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5180 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5181 break;
5182 }
5183 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5184 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5185 break;
5186 }
5187 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5188 ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5189 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5190 break;
5191 }
5192 case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5193 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5194 break;
5195 }
5196 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5197 ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5198 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5199 break;
5200 }
5201 case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5202 snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5203 break;
5204 }
5205 case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5206 snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5207 break;
5208 }
5209 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5210 int index = 0;
5211 char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5212 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5213 if (route_rule != NULL) {
5214 for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5215 if (route_rule->exception_if_indices[index] != 0) {
5216 ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5217 snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5218 } else {
5219 memset(interface_names[index], 0, IFXNAMSIZ);
5220 }
5221 }
5222 switch (route_rule->default_action) {
5223 case NECP_ROUTE_RULE_DENY_INTERFACE:
5224 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5225 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%s)",
5226 (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5227 (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5228 (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5229 (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5230 (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5231 (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Ultra-Constrained " : "",
5232 (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5233 (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5234 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5235 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5236 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5237 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5238 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5239 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5240 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5241 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5242 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5243 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5244 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5245 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5246 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5247 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5248 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5249 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5250 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5251 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5252 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5253 break;
5254 case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5255 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%s)",
5256 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5257 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5258 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5259 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5260 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5261 IS_NECP_ROUTE_RULE_DENY(route_rule->ultra_constrained_action) ? "!Ultra-Constrained " : "",
5262 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5263 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5264 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5265 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5266 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5267 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5268 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5269 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5270 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5271 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5272 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5273 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5274 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5275 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5276 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5277 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5278 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5279 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5280 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5281 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5282 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5283 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5284 break;
5285 case NECP_ROUTE_RULE_QOS_MARKING:
5286 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%s)",
5287 (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5288 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5289 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5290 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5291 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5292 (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Ultra-Constrained " : "",
5293 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5294 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5295 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5296 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5297 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5298 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5299 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5300 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5301 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5302 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5303 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5304 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5305 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5306 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5307 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5308 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5309 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5310 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5311 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5312 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5313 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5314 break;
5315 default:
5316 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5317 break;
5318 }
5319 }
5320 break;
5321 }
5322 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5323 bool found_mapping = FALSE;
5324 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(result_parameter.netagent_id);
5325 if (mapping != NULL) {
5326 uuid_unparse(mapping->uuid, uuid_string);
5327 found_mapping = TRUE;
5328 }
5329 snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5330 break;
5331 }
5332 case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5333 bool found_mapping = FALSE;
5334 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(result_parameter.netagent_id);
5335 if (mapping != NULL) {
5336 uuid_unparse(mapping->uuid, uuid_string);
5337 found_mapping = TRUE;
5338 }
5339 snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5340 break;
5341 }
5342 case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5343 bool found_mapping = FALSE;
5344 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(result_parameter.netagent_id);
5345 if (mapping != NULL) {
5346 uuid_unparse(mapping->uuid, uuid_string);
5347 found_mapping = TRUE;
5348 }
5349 snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5350 break;
5351 }
5352 case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT_TYPE: {
5353 bool found_mapping = FALSE;
5354 struct necp_agent_type_id_mapping *mapping = necp_lookup_agent_type_with_id_locked(result_parameter.netagent_id);
5355 if (mapping != NULL) {
5356 found_mapping = TRUE;
5357 }
5358 snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgentType (%s/%s)", found_mapping ? mapping->agent_type.agent_domain : "Unknown", found_mapping ? mapping->agent_type.agent_type : "Unknown");
5359 break;
5360 }
5361 default: {
5362 snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5363 break;
5364 }
5365 }
5366 return result_string;
5367 }
5368
5369 static void
necp_kernel_socket_policies_dump_all(void)5370 necp_kernel_socket_policies_dump_all(void)
5371 {
5372 if (necp_debug) {
5373 struct necp_kernel_socket_policy *policy = NULL;
5374 int policy_i;
5375 int app_i;
5376 char result_string[MAX_RESULT_STRING_LEN];
5377 char proc_name_string[MAXCOMLEN + 1];
5378 memset(result_string, 0, MAX_RESULT_STRING_LEN);
5379 memset(proc_name_string, 0, MAXCOMLEN + 1);
5380
5381 NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5382 NECPLOG0(LOG_DEBUG, "-----------\n");
5383 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5384 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5385 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5386 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));
5387 }
5388 if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5389 NECPLOG0(LOG_DEBUG, "-----------\n");
5390 }
5391
5392 NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5393 NECPLOG0(LOG_DEBUG, "-----------\n");
5394 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5395 NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5396 for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5397 policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5398 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5399 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));
5400 }
5401 NECPLOG0(LOG_DEBUG, "-----------\n");
5402 }
5403 }
5404 }
5405
5406 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5407 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5408 {
5409 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5410 // Drop always cancels out lower policies
5411 return TRUE;
5412 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5413 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5414 upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5415 upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5416 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5417 upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT ||
5418 upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT_TYPE) {
5419 // Filters and route rules never cancel out lower policies
5420 return FALSE;
5421 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5422 if (upper_policy->session_order != lower_policy->session_order) {
5423 // A skip cannot override a policy of a different session
5424 return FALSE;
5425 } else {
5426 if (upper_policy->result_parameter.skip_policy_order == 0 ||
5427 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5428 // This policy is beyond the skip
5429 return FALSE;
5430 } else {
5431 // This policy is inside the skip
5432 return TRUE;
5433 }
5434 }
5435 }
5436
5437 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5438 return TRUE;
5439 }
5440
5441 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)5442 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5443 {
5444 bool can_skip = FALSE;
5445 u_int32_t highest_skip_session_order = 0;
5446 u_int32_t highest_skip_order = 0;
5447 int i;
5448 for (i = 0; i < valid_indices; i++) {
5449 struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5450
5451 // For policies in a skip window, we can't mark conflicting policies as unnecessary
5452 if (can_skip) {
5453 if (highest_skip_session_order != compared_policy->session_order ||
5454 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5455 // If we've moved on to the next session, or passed the skip window
5456 highest_skip_session_order = 0;
5457 highest_skip_order = 0;
5458 can_skip = FALSE;
5459 } else {
5460 // If this policy is also a skip, in can increase the skip window
5461 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5462 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5463 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5464 }
5465 }
5466 continue;
5467 }
5468 }
5469
5470 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5471 // This policy is a skip. Set the skip window accordingly
5472 can_skip = TRUE;
5473 highest_skip_session_order = compared_policy->session_order;
5474 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5475 }
5476
5477 // The result of the compared policy must be able to block out this policy result
5478 if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5479 continue;
5480 }
5481
5482 // If new policy matches All Interfaces, compared policy must also
5483 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5484 continue;
5485 }
5486
5487 // If new policy matches Local Networks, compared policy must also
5488 if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5489 policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5490 continue;
5491 }
5492
5493 // Default makes lower policies unecessary always
5494 if (compared_policy->condition_mask == 0) {
5495 return TRUE;
5496 }
5497
5498 // Compared must be more general than policy, and include only conditions within policy
5499 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5500 continue;
5501 }
5502
5503 // Negative conditions must match for the overlapping conditions
5504 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5505 continue;
5506 }
5507
5508 if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5509 compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5510 strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5511 continue;
5512 }
5513
5514 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5515 compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5516 continue;
5517 }
5518
5519 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5520 strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5521 continue;
5522 }
5523
5524 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5525 strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5526 continue;
5527 }
5528
5529 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5530 compared_policy->cond_account_id != policy->cond_account_id) {
5531 continue;
5532 }
5533
5534 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5535 compared_policy->cond_policy_id != policy->cond_policy_id) {
5536 continue;
5537 }
5538
5539 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5540 compared_policy->cond_app_id != policy->cond_app_id) {
5541 continue;
5542 }
5543
5544 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5545 compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5546 continue;
5547 }
5548
5549 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5550 (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5551 continue;
5552 }
5553
5554 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5555 compared_policy->cond_uid != policy->cond_uid) {
5556 continue;
5557 }
5558
5559 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5560 compared_policy->cond_real_uid != policy->cond_real_uid) {
5561 continue;
5562 }
5563
5564 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5565 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5566 continue;
5567 }
5568
5569 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5570 compared_policy->cond_protocol != policy->cond_protocol) {
5571 continue;
5572 }
5573
5574 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5575 compared_policy->cond_client_flags != policy->cond_client_flags) {
5576 continue;
5577 }
5578
5579 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5580 !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5581 compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5582 continue;
5583 }
5584
5585 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5586 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5587 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))) {
5588 continue;
5589 }
5590 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5591 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5592 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5593 continue;
5594 }
5595 }
5596 }
5597
5598 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5599 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5600 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))) {
5601 continue;
5602 }
5603 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5604 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5605 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5606 continue;
5607 }
5608 }
5609 }
5610
5611 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5612 memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5613 continue;
5614 }
5615
5616 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5617 memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5618 continue;
5619 }
5620
5621 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5622 memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5623 continue;
5624 }
5625
5626 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5627 memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5628 continue;
5629 }
5630
5631 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5632 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5633 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5634 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5635 continue;
5636 }
5637
5638 return TRUE;
5639 }
5640
5641 return FALSE;
5642 }
5643
5644 static bool
necp_kernel_socket_policies_reprocess(void)5645 necp_kernel_socket_policies_reprocess(void)
5646 {
5647 int app_i;
5648 int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5649 int app_layer_current_free_index = 0;
5650 struct necp_kernel_socket_policy *kernel_policy = NULL;
5651
5652 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5653
5654 // Reset mask to 0
5655 necp_kernel_application_policies_condition_mask = 0;
5656 necp_kernel_socket_policies_condition_mask = 0;
5657 necp_kernel_application_policies_count = 0;
5658 necp_kernel_socket_policies_count = 0;
5659 necp_kernel_socket_policies_non_app_count = 0;
5660
5661 // Reset all maps to NULL
5662 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5663 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5664 kfree_type(struct necp_kernel_socket_policy *,
5665 necp_kernel_socket_policies_map_counts[app_i] + 1,
5666 necp_kernel_socket_policies_map[app_i]);
5667 necp_kernel_socket_policies_map[app_i] = NULL;
5668 }
5669
5670 // Init counts
5671 necp_kernel_socket_policies_map_counts[app_i] = 0;
5672 }
5673 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5674 kfree_type(struct necp_kernel_socket_policy *,
5675 necp_kernel_socket_policies_app_layer_map_count + 1,
5676 necp_kernel_socket_policies_app_layer_map);
5677 }
5678 necp_kernel_socket_policies_app_layer_map = NULL;
5679 necp_kernel_socket_policies_app_layer_map_count = 0;
5680
5681 // Create masks and counts
5682 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5683 // App layer mask/count
5684 necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5685 necp_kernel_application_policies_count++;
5686 necp_kernel_socket_policies_app_layer_map_count++;
5687
5688 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5689 // Agent type conditions only apply to app layer
5690 continue;
5691 }
5692
5693 // Update socket layer bucket mask/counts
5694 necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5695 necp_kernel_socket_policies_count++;
5696
5697 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5698 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5699 necp_kernel_socket_policies_non_app_count++;
5700 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5701 necp_kernel_socket_policies_map_counts[app_i]++;
5702 }
5703 } else {
5704 necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5705 }
5706 }
5707
5708 // Allocate maps
5709 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5710 if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5711 // Allocate a NULL-terminated array of policy pointers for each bucket
5712 necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5713 necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5714 if (necp_kernel_socket_policies_map[app_i] == NULL) {
5715 goto fail;
5716 }
5717 }
5718 bucket_current_free_index[app_i] = 0;
5719 }
5720 necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5721 necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5722 if (necp_kernel_socket_policies_app_layer_map == NULL) {
5723 goto fail;
5724 }
5725
5726 // Fill out maps
5727 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5728 // Add app layer policies
5729 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5730 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5731 app_layer_current_free_index++;
5732 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5733 }
5734
5735 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5736 // Agent type conditions only apply to app layer
5737 continue;
5738 }
5739
5740 // Add socket policies
5741 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5742 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5743 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5744 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])) {
5745 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5746 bucket_current_free_index[app_i]++;
5747 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5748 }
5749 }
5750 } else {
5751 app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5752 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])) {
5753 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5754 bucket_current_free_index[app_i]++;
5755 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5756 }
5757 }
5758 }
5759 necp_kernel_socket_policies_dump_all();
5760 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5761 return TRUE;
5762
5763 fail:
5764 // Free memory, reset masks to 0
5765 necp_kernel_application_policies_condition_mask = 0;
5766 necp_kernel_socket_policies_condition_mask = 0;
5767 necp_kernel_application_policies_count = 0;
5768 necp_kernel_socket_policies_count = 0;
5769 necp_kernel_socket_policies_non_app_count = 0;
5770 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5771 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5772 kfree_type(struct necp_kernel_socket_policy *,
5773 necp_kernel_socket_policies_map_counts[app_i] + 1,
5774 necp_kernel_socket_policies_map[app_i]);
5775 necp_kernel_socket_policies_map[app_i] = NULL;
5776 }
5777 necp_kernel_socket_policies_map_counts[app_i] = 0;
5778 }
5779 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5780 kfree_type(struct necp_kernel_socket_policy *,
5781 necp_kernel_socket_policies_app_layer_map_count + 1,
5782 necp_kernel_socket_policies_app_layer_map);
5783 necp_kernel_socket_policies_app_layer_map = NULL;
5784 }
5785 necp_kernel_socket_policies_app_layer_map_count = 0;
5786 return FALSE;
5787 }
5788
5789 static u_int32_t
necp_get_new_string_id(void)5790 necp_get_new_string_id(void)
5791 {
5792 static u_int32_t necp_last_string_id = 0;
5793
5794 u_int32_t newid = 0;
5795
5796 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5797
5798 bool wrapped = FALSE;
5799 do {
5800 necp_last_string_id++;
5801 if (necp_last_string_id < 1) {
5802 if (wrapped) {
5803 // Already wrapped, give up
5804 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5805 return 0;
5806 }
5807 necp_last_string_id = 1;
5808 wrapped = TRUE;
5809 }
5810 newid = necp_last_string_id;
5811 } while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5812
5813 if (newid == 0) {
5814 NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5815 return 0;
5816 }
5817
5818 return newid;
5819 }
5820
5821 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5822 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5823 {
5824 struct necp_string_id_mapping *searchentry = NULL;
5825 struct necp_string_id_mapping *foundentry = NULL;
5826
5827 LIST_FOREACH(searchentry, list, chain) {
5828 if (strcmp(searchentry->string, string) == 0) {
5829 foundentry = searchentry;
5830 break;
5831 }
5832 }
5833
5834 return foundentry;
5835 }
5836
5837 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5838 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5839 {
5840 struct necp_string_id_mapping *searchentry = NULL;
5841 struct necp_string_id_mapping *foundentry = NULL;
5842
5843 LIST_FOREACH(searchentry, list, chain) {
5844 if (searchentry->id == local_id) {
5845 foundentry = searchentry;
5846 break;
5847 }
5848 }
5849
5850 return foundentry;
5851 }
5852
5853 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5854 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5855 {
5856 u_int32_t string_id = 0;
5857 struct necp_string_id_mapping *existing_mapping = NULL;
5858
5859 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5860
5861 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5862 if (existing_mapping != NULL) {
5863 string_id = existing_mapping->id;
5864 os_ref_retain_locked(&existing_mapping->refcount);
5865 } else {
5866 struct necp_string_id_mapping * __single new_mapping = NULL;
5867 new_mapping = kalloc_type(struct necp_string_id_mapping,
5868 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5869
5870 size_t length = strlen(string) + 1;
5871 char *buffer = kalloc_data(length, Z_WAITOK);
5872 if (buffer != NULL) {
5873 strlcpy(buffer, string, length);
5874 new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5875 new_mapping->id = necp_get_new_string_id();
5876 os_ref_init(&new_mapping->refcount, &necp_refgrp);
5877 LIST_INSERT_HEAD(list, new_mapping, chain);
5878 string_id = new_mapping->id;
5879 } else {
5880 kfree_type(struct necp_string_id_mapping, new_mapping);
5881 new_mapping = NULL;
5882 }
5883 }
5884 return string_id;
5885 }
5886
5887 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5888 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5889 {
5890 struct necp_string_id_mapping * __single existing_mapping = NULL;
5891 char * __indexable buffer = NULL;
5892
5893 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5894
5895 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5896 if (existing_mapping != NULL) {
5897 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5898 LIST_REMOVE(existing_mapping, chain);
5899 buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5900 kfree_data_addr(buffer);
5901 kfree_type(struct necp_string_id_mapping, existing_mapping);
5902 }
5903 return TRUE;
5904 }
5905
5906 return FALSE;
5907 }
5908
5909 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5910 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5911 {
5912 struct necp_domain_filter *searchfilter = NULL;
5913 struct necp_domain_filter *foundfilter = NULL;
5914
5915 LIST_FOREACH(searchfilter, list, chain) {
5916 if (searchfilter->id == filter_id) {
5917 foundfilter = searchfilter;
5918 break;
5919 }
5920 }
5921
5922 return foundfilter;
5923 }
5924
5925 static u_int32_t
necp_get_new_domain_filter_id(void)5926 necp_get_new_domain_filter_id(void)
5927 {
5928 static u_int32_t necp_last_filter_id = 0;
5929
5930 u_int32_t newid = 0;
5931
5932 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5933
5934 bool wrapped = FALSE;
5935 do {
5936 // Scope id within its space
5937 if (++necp_last_filter_id > NECP_DOMAIN_FILTER_ID_MAX) {
5938 necp_last_filter_id = 0;
5939 }
5940 if (necp_last_filter_id < 1) {
5941 if (wrapped) {
5942 // Already wrapped, give up
5943 NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5944 return 0;
5945 }
5946 necp_last_filter_id = 1;
5947 wrapped = TRUE;
5948 }
5949 newid = necp_last_filter_id;
5950 } while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5951
5952 if (newid == 0) {
5953 NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5954 return 0;
5955 }
5956
5957 return newid;
5958 }
5959
5960 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)5961 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5962 {
5963 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5964
5965 struct necp_domain_filter *new_filter = NULL;
5966 new_filter = kalloc_type(struct necp_domain_filter,
5967 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5968
5969 new_filter->filter = filter;
5970 new_filter->id = necp_get_new_domain_filter_id();
5971 LIST_INSERT_HEAD(list, new_filter, chain);
5972 LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
5973 os_ref_init(&new_filter->refcount, &necp_refgrp);
5974
5975 return new_filter->id;
5976 }
5977
5978 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)5979 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
5980 {
5981 struct necp_domain_filter * __single existing_filter = NULL;
5982
5983 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5984
5985 existing_filter = necp_lookup_domain_filter(list, filter_id);
5986 if (existing_filter != NULL) {
5987 if (os_ref_release_locked(&existing_filter->refcount) == 0) {
5988 LIST_REMOVE(existing_filter, chain);
5989 LIST_REMOVE(existing_filter, owner_chain);
5990 net_bloom_filter_destroy(existing_filter->filter);
5991 kfree_type(struct necp_domain_filter, existing_filter);
5992 }
5993 return true;
5994 }
5995
5996 return false;
5997 }
5998
5999 static struct necp_domain_trie *
necp_lookup_domain_trie(struct necp_domain_trie_list * list,u_int32_t id)6000 necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id)
6001 {
6002 struct necp_domain_trie *searchTrie = NULL;
6003 struct necp_domain_trie *foundTrie = NULL;
6004
6005 LIST_FOREACH(searchTrie, list, chain) {
6006 if (searchTrie->id == id) {
6007 foundTrie = searchTrie;
6008 break;
6009 }
6010 }
6011
6012 return foundTrie;
6013 }
6014
6015 static u_int32_t
necp_get_new_domain_trie_id(void)6016 necp_get_new_domain_trie_id(void)
6017 {
6018 static u_int32_t necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START;
6019 u_int32_t newid = necp_last_trie_id;
6020
6021 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6022
6023 bool wrapped = FALSE;
6024 do {
6025 if (++necp_last_trie_id < NECP_DOMAIN_TRIE_ID_START + 1) {
6026 if (wrapped) {
6027 // Already wrapped, give up
6028 NECPLOG0(LOG_ERR, "Failed to find a free trie ID.\n");
6029 return 0;
6030 }
6031 necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START + 1;
6032 wrapped = TRUE;
6033 }
6034 newid = necp_last_trie_id;
6035 } while (necp_lookup_domain_trie(&necp_global_domain_trie_list, newid) != NULL); // If already used, keep trying
6036
6037 if (newid == NECP_DOMAIN_TRIE_ID_START) {
6038 NECPLOG0(LOG_ERR, "Allocate trie id failed.\n");
6039 return 0;
6040 }
6041
6042 return newid;
6043 }
6044
6045 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)6046 necp_create_domain_trie(struct necp_domain_trie_list *list,
6047 struct necp_domain_trie_list *owner_list,
6048 struct necp_domain_trie_request *trie_request, size_t trie_request_size)
6049 {
6050 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6051
6052 struct necp_domain_trie *new_trie = NULL;
6053 new_trie = kalloc_type(struct necp_domain_trie, Z_WAITOK | Z_ZERO | Z_NOFAIL);
6054 if (new_trie == NULL) {
6055 NECPLOG0(LOG_ERR, "Failed to allow domain trie\n");
6056 return 0;
6057 }
6058
6059 if (net_trie_init_with_mem(&new_trie->trie, trie_request->data, trie_request->total_mem_size,
6060 trie_request->nodes_mem_size, trie_request->maps_mem_size, trie_request->bytes_mem_size,
6061 trie_request->nodes_count, trie_request->maps_count, trie_request->bytes_count) == false) {
6062 NECPLOG0(LOG_ERR, "Failed to initialize domain trie\n");
6063 kfree_type(struct necp_domain_trie, new_trie);
6064 return 0;
6065 }
6066 new_trie->trie_request = trie_request;
6067 new_trie->trie_request_size = trie_request_size;
6068 new_trie->id = necp_get_new_domain_trie_id();
6069 new_trie->trie_request->id = new_trie->id;
6070 LIST_INSERT_HEAD(list, new_trie, chain);
6071 LIST_INSERT_HEAD(owner_list, new_trie, owner_chain);
6072
6073 os_ref_init(&new_trie->refcount, &necp_refgrp);
6074 necp_trie_count++;
6075 return new_trie->id;
6076 }
6077
6078 static void
necp_free_domain_trie(struct necp_domain_trie * existing_trie)6079 necp_free_domain_trie(struct necp_domain_trie *existing_trie)
6080 {
6081 if (existing_trie != NULL) {
6082 uint8_t *necp_trie_request_buffer = (uint8_t *)existing_trie->trie_request;
6083 kfree_data(necp_trie_request_buffer, existing_trie->trie_request_size);
6084 kfree_type(struct necp_domain_trie, existing_trie);
6085 }
6086 }
6087
6088 static bool
necp_remove_domain_trie(struct necp_domain_trie_list * list,__unused struct necp_domain_trie_list * owner_list,u_int32_t id)6089 necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id)
6090 {
6091 struct necp_domain_trie * __single existing_trie = NULL;
6092
6093 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6094
6095 existing_trie = necp_lookup_domain_trie(list, id);
6096 if (existing_trie != NULL) {
6097 if (os_ref_release_locked(&existing_trie->refcount) == 0) {
6098 LIST_REMOVE(existing_trie, chain);
6099 LIST_REMOVE(existing_trie, owner_chain);
6100 necp_free_domain_trie(existing_trie);
6101 necp_trie_count--;
6102 }
6103 return true;
6104 }
6105
6106 return false;
6107 }
6108
6109 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)6110 necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length)
6111 {
6112 size_t metadata_length = 0;
6113 const uint8_t * __sized_by(metadata_length) metadata = NULL;
6114
6115 struct necp_domain_trie *necp_trie = necp_lookup_domain_trie(list, id);
6116 if (necp_trie == NULL || necp_trie->trie_request == NULL) {
6117 return false;
6118 }
6119 Boolean reverse = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_REVERSE_SEARCH);
6120 Boolean allow_partial_match = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_ALLOW_PARTIAL_MATCH);
6121 return net_trie_search(&necp_trie->trie, (const uint8_t *)domain, length,
6122 &metadata, &metadata_length, reverse, allow_partial_match, necp_trie->trie_request->partial_match_terminator, NULL, NULL) != NULL_TRIE_IDX;
6123 }
6124
6125 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
6126 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
6127 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)6128 necp_get_new_route_rule_id(bool aggregate)
6129 {
6130 static u_int32_t necp_last_route_rule_id = 0;
6131 static u_int32_t necp_last_aggregate_route_rule_id = 0;
6132
6133 u_int32_t newid = 0;
6134
6135 if (!aggregate) {
6136 // Main necp_kernel_policy_lock protects non-aggregate rule IDs
6137 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6138
6139 bool wrapped = FALSE;
6140 do {
6141 necp_last_route_rule_id++;
6142 if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
6143 necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6144 if (wrapped) {
6145 // Already wrapped, give up
6146 NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
6147 return 0;
6148 }
6149 necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
6150 wrapped = TRUE;
6151 }
6152 newid = necp_last_route_rule_id;
6153 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6154 } else {
6155 // necp_route_rule_lock protects aggregate rule IDs
6156 LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
6157
6158 bool wrapped = FALSE;
6159 do {
6160 necp_last_aggregate_route_rule_id++;
6161 if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6162 if (wrapped) {
6163 // Already wrapped, give up
6164 NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
6165 return 0;
6166 }
6167 necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
6168 wrapped = TRUE;
6169 }
6170 newid = necp_last_aggregate_route_rule_id;
6171 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6172 }
6173
6174 if (newid == 0) {
6175 NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
6176 return 0;
6177 }
6178
6179 return newid;
6180 }
6181
6182 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)6183 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6184 {
6185 struct necp_route_rule *searchentry = NULL;
6186 struct necp_route_rule *foundentry = NULL;
6187
6188 LIST_FOREACH(searchentry, list, chain) {
6189 if (searchentry->id == route_rule_id) {
6190 foundentry = searchentry;
6191 break;
6192 }
6193 }
6194
6195 return foundentry;
6196 }
6197
6198 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_int8_t ultra_constrained_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)6199 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_int8_t ultra_constrained_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)
6200 {
6201 struct necp_route_rule *searchentry = NULL;
6202 struct necp_route_rule *foundentry = NULL;
6203
6204 LIST_FOREACH(searchentry, list, chain) {
6205 if (searchentry->default_action == default_action &&
6206 searchentry->cellular_action == cellular_action &&
6207 searchentry->wifi_action == wifi_action &&
6208 searchentry->wired_action == wired_action &&
6209 searchentry->expensive_action == expensive_action &&
6210 searchentry->constrained_action == constrained_action &&
6211 searchentry->companion_action == companion_action &&
6212 searchentry->vpn_action == vpn_action &&
6213 searchentry->ultra_constrained_action == ultra_constrained_action &&
6214 searchentry->control_unit == control_unit &&
6215 searchentry->effective_type == effective_type) {
6216 bool match_failed = FALSE;
6217 size_t index_a = 0;
6218 size_t index_b = 0;
6219 size_t count_a = 0;
6220 size_t count_b = 0;
6221 for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
6222 bool found_index = FALSE;
6223 if (searchentry->exception_if_indices[index_a] == 0) {
6224 break;
6225 }
6226 count_a++;
6227 for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
6228 if (if_indices[index_b] == 0) {
6229 break;
6230 }
6231 if (index_b >= count_b) {
6232 count_b = index_b + 1;
6233 }
6234 if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
6235 searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
6236 found_index = TRUE;
6237 break;
6238 }
6239 }
6240 if (!found_index) {
6241 match_failed = TRUE;
6242 break;
6243 }
6244 }
6245
6246 if (match_failed || count_a != count_b) {
6247 continue;
6248 }
6249
6250 bool has_agent_a = !uuid_is_null(netagent_uuid);
6251 bool has_agent_b = (searchentry->netagent_id != 0);
6252 if (has_agent_a != has_agent_b) {
6253 continue;
6254 }
6255
6256 if (has_agent_a) {
6257 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(searchentry->netagent_id);
6258 if (mapping == NULL) {
6259 // Bad mapping, doesn't match
6260 continue;
6261 }
6262 if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
6263 // UUIDs don't match
6264 continue;
6265 }
6266 }
6267
6268 bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
6269 bool has_match_agent_b = (searchentry->match_netagent_id != 0);
6270 if (has_match_agent_a != has_match_agent_b) {
6271 continue;
6272 }
6273
6274 if (has_match_agent_a) {
6275 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(searchentry->match_netagent_id);
6276 if (mapping == NULL) {
6277 // Bad mapping, doesn't match
6278 continue;
6279 }
6280 if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
6281 // UUIDs don't match
6282 continue;
6283 }
6284 }
6285
6286 // Rules match!
6287 foundentry = searchentry;
6288 break;
6289 }
6290 }
6291
6292 return foundentry;
6293 }
6294
6295 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)6296 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,
6297 bool *has_socket_only_actions)
6298 {
6299 size_t offset = 0;
6300 u_int32_t route_rule_id = 0;
6301 struct necp_route_rule *existing_rule = NULL;
6302 u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
6303 u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
6304 u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
6305 u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
6306 u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
6307 u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
6308 u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
6309 u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
6310 u_int8_t ultra_constrained_action = NECP_ROUTE_RULE_NONE;
6311 u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
6312 size_t num_valid_indices = 0;
6313 memset(&if_indices, 0, sizeof(if_indices));
6314 u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
6315 memset(&if_actions, 0, sizeof(if_actions));
6316
6317 uuid_t netagent_uuid = {};
6318
6319 uuid_t match_netagent_uuid = {};
6320 uint32_t control_unit = 0;
6321 uint32_t effective_type = 0;
6322
6323 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6324
6325 if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6326 return 0;
6327 }
6328
6329 // Process rules
6330 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6331 ifnet_t __single rule_interface = NULL;
6332 char interface_name[IFXNAMSIZ];
6333 u_int32_t length = 0;
6334 u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6335
6336 if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6337 // Invalid TLV goes beyond end of the rules array
6338 break;
6339 }
6340
6341 // Increment offset for the next time through the loop
6342 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6343
6344 u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6345 u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6346 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6347 u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6348
6349 if (rule_action == NECP_ROUTE_RULE_NONE) {
6350 // Don't allow an explicit rule to be None action
6351 continue;
6352 }
6353
6354 if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6355 rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6356 if (rule_length < sizeof(uuid_t)) {
6357 // Too short, skip
6358 continue;
6359 }
6360
6361 if (!uuid_is_null(netagent_uuid)) {
6362 if (uuid_compare(netagent_uuid, rule_value) != 0) {
6363 // UUIDs don't match, skip
6364 continue;
6365 }
6366 } else {
6367 // Copy out agent UUID
6368 memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6369 }
6370
6371 // Adjust remaining length
6372 rule_value += sizeof(netagent_uuid);
6373 rule_length -= sizeof(netagent_uuid);
6374 *has_socket_only_actions = true;
6375 } else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6376 if (rule_length < sizeof(control_unit)) {
6377 // Too short, skip
6378 continue;
6379 }
6380
6381 memcpy(&control_unit, rule_value, sizeof(control_unit));
6382
6383 // Adjust remaining length
6384 rule_value += sizeof(control_unit);
6385 rule_length -= sizeof(control_unit);
6386 *has_socket_only_actions = true;
6387 } else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6388 if (rule_length < sizeof(effective_type)) {
6389 // Too short, skip
6390 continue;
6391 }
6392
6393 memcpy(&effective_type, rule_value, sizeof(effective_type));
6394
6395 // Adjust remaining length
6396 rule_value += sizeof(effective_type);
6397 rule_length -= sizeof(effective_type);
6398 }
6399
6400 if (rule_length == 0) {
6401 if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6402 cellular_action = rule_action;
6403 }
6404 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6405 wifi_action = rule_action;
6406 }
6407 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6408 wired_action = rule_action;
6409 }
6410 if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6411 expensive_action = rule_action;
6412 }
6413 if ((rule_flags & NECP_ROUTE_RULE_FLAG_ULTRA_CONSTRAINED) == NECP_ROUTE_RULE_FLAG_ULTRA_CONSTRAINED) {
6414 ultra_constrained_action = rule_action;
6415 } else if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6416 constrained_action = rule_action;
6417 }
6418 if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6419 companion_action = rule_action;
6420 }
6421 if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6422 vpn_action = rule_action;
6423 }
6424 if (rule_flags == 0) {
6425 default_action = rule_action;
6426 }
6427 continue;
6428 } else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6429 if (rule_length < sizeof(uuid_t)) {
6430 // Too short, skip
6431 continue;
6432 }
6433
6434 // Store the netagent UUID to match
6435 memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6436 // If the data is exactly a UUID, this is the default action
6437 if (rule_length == sizeof(uuid_t)) {
6438 default_action = rule_action;
6439 continue;
6440 }
6441
6442 // If the data is longer than a UUID, this also includes an interface name
6443 // Adjust remaining length to make sure the interface name is picked up below
6444 rule_value += sizeof(uuid_t);
6445 rule_length -= sizeof(uuid_t);
6446 }
6447
6448 if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6449 continue;
6450 }
6451
6452 if (rule_length <= IFXNAMSIZ) {
6453 memcpy(interface_name, rule_value, rule_length);
6454 interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6455 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6456 if_actions[num_valid_indices] = rule_action;
6457 if_indices[num_valid_indices++] = rule_interface->if_index;
6458 ifnet_release(rule_interface);
6459 }
6460 }
6461 }
6462
6463 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, ultra_constrained_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit, effective_type);
6464 if (existing_rule != NULL) {
6465 route_rule_id = existing_rule->id;
6466 os_ref_retain_locked(&existing_rule->refcount);
6467 } else {
6468 struct necp_route_rule *new_rule = NULL;
6469 new_rule = kalloc_type(struct necp_route_rule,
6470 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6471 route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6472 if (!uuid_is_null(netagent_uuid)) {
6473 new_rule->netagent_id = necp_create_agent_uuid_id_mapping(netagent_uuid);
6474 }
6475 if (!uuid_is_null(match_netagent_uuid)) {
6476 new_rule->match_netagent_id = necp_create_agent_uuid_id_mapping(match_netagent_uuid);
6477 }
6478 new_rule->effective_type = effective_type;
6479 new_rule->control_unit = control_unit;
6480 new_rule->default_action = default_action;
6481 new_rule->cellular_action = cellular_action;
6482 new_rule->wifi_action = wifi_action;
6483 new_rule->wired_action = wired_action;
6484 new_rule->expensive_action = expensive_action;
6485 new_rule->constrained_action = constrained_action;
6486 new_rule->companion_action = companion_action;
6487 new_rule->vpn_action = vpn_action;
6488 new_rule->ultra_constrained_action = ultra_constrained_action;
6489 memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6490 memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6491 os_ref_init(&new_rule->refcount, &necp_refgrp);
6492 LIST_INSERT_HEAD(list, new_rule, chain);
6493 }
6494 return route_rule_id;
6495 }
6496
6497 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6498 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6499 {
6500 if (rule_id) {
6501 lck_rw_lock_exclusive(&necp_route_rule_lock);
6502
6503 struct necp_aggregate_route_rule * __single existing_rule = NULL;
6504 struct necp_aggregate_route_rule *tmp_rule = NULL;
6505
6506 LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6507 int index = 0;
6508 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6509 u_int32_t route_rule_id = existing_rule->rule_ids[index];
6510 if (route_rule_id == rule_id) {
6511 LIST_REMOVE(existing_rule, chain);
6512 kfree_type(struct necp_aggregate_route_rule, existing_rule);
6513 break;
6514 }
6515 }
6516 }
6517
6518 lck_rw_done(&necp_route_rule_lock);
6519 }
6520 }
6521
6522 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6523 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6524 {
6525 struct necp_route_rule * __single existing_rule = NULL;
6526
6527 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6528
6529 existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6530 if (existing_rule != NULL) {
6531 if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6532 necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6533 necp_remove_agent_uuid_id_mapping_with_agent_id(existing_rule->netagent_id);
6534 necp_remove_agent_uuid_id_mapping_with_agent_id(existing_rule->match_netagent_id);
6535 LIST_REMOVE(existing_rule, chain);
6536 kfree_type(struct necp_route_rule, existing_rule);
6537 }
6538 return TRUE;
6539 }
6540
6541 return FALSE;
6542 }
6543
6544 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6545 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6546 {
6547 struct necp_aggregate_route_rule *searchentry = NULL;
6548 struct necp_aggregate_route_rule *foundentry = NULL;
6549
6550 lck_rw_lock_shared(&necp_route_rule_lock);
6551
6552 LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6553 if (searchentry->id == route_rule_id) {
6554 foundentry = searchentry;
6555 break;
6556 }
6557 }
6558
6559 lck_rw_done(&necp_route_rule_lock);
6560
6561 return foundentry;
6562 }
6563
6564 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6565 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6566 {
6567 u_int32_t aggregate_route_rule_id = 0;
6568 struct necp_aggregate_route_rule *new_rule = NULL;
6569 struct necp_aggregate_route_rule *existing_rule = NULL;
6570
6571 lck_rw_lock_exclusive(&necp_route_rule_lock);
6572
6573 // Check if the rule already exists
6574 LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6575 if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6576 lck_rw_done(&necp_route_rule_lock);
6577 return existing_rule->id;
6578 }
6579 }
6580
6581 new_rule = kalloc_type(struct necp_aggregate_route_rule,
6582 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6583 aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6584 new_rule->id = aggregate_route_rule_id;
6585 memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6586 LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6587 lck_rw_done(&necp_route_rule_lock);
6588
6589 return aggregate_route_rule_id;
6590 }
6591
6592 static u_int32_t
necp_get_new_app_uuid_id(void)6593 necp_get_new_app_uuid_id(void)
6594 {
6595 static u_int32_t necp_last_app_uuid_id = 0;
6596
6597 u_int32_t newid = 0;
6598
6599 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6600
6601 bool wrapped = FALSE;
6602 do {
6603 necp_last_app_uuid_id++;
6604 if (necp_last_app_uuid_id < 1) {
6605 if (wrapped) {
6606 // Already wrapped, give up
6607 NECPLOG0(LOG_ERR, "Failed to find a free app UUID ID.\n");
6608 return 0;
6609 }
6610 necp_last_app_uuid_id = 1;
6611 wrapped = TRUE;
6612 }
6613 newid = necp_last_app_uuid_id;
6614 } while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6615
6616 if (newid == 0) {
6617 NECPLOG0(LOG_ERR, "Allocate app UUID ID failed.\n");
6618 return 0;
6619 }
6620
6621 return newid;
6622 }
6623
6624 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6625 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6626 {
6627 struct necp_uuid_id_mapping *searchentry = NULL;
6628 struct necp_uuid_id_mapping *foundentry = NULL;
6629
6630 LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6631 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6632 foundentry = searchentry;
6633 break;
6634 }
6635 }
6636
6637 return foundentry;
6638 }
6639
6640 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6641 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6642 {
6643 struct necp_uuid_id_mapping *searchentry = NULL;
6644 struct necp_uuid_id_mapping *foundentry = NULL;
6645
6646 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6647 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--) {
6648 LIST_FOREACH(searchentry, uuid_list_head, chain) {
6649 if (searchentry->id == local_id) {
6650 foundentry = searchentry;
6651 break;
6652 }
6653 }
6654 }
6655
6656 return foundentry;
6657 }
6658
6659 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6660 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6661 {
6662 u_int32_t local_id = 0;
6663 struct necp_uuid_id_mapping *existing_mapping = NULL;
6664
6665 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6666
6667 if (allocated_mapping) {
6668 *allocated_mapping = FALSE;
6669 }
6670
6671 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6672 if (existing_mapping != NULL) {
6673 local_id = existing_mapping->id;
6674 os_ref_retain_locked(&existing_mapping->refcount);
6675 if (uuid_policy_table) {
6676 existing_mapping->table_usecount++;
6677 }
6678 } else {
6679 struct necp_uuid_id_mapping *new_mapping = NULL;
6680 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6681 Z_WAITOK | Z_NOFAIL);
6682 uuid_copy(new_mapping->uuid, uuid);
6683 new_mapping->id = necp_get_new_app_uuid_id();
6684 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6685 if (uuid_policy_table) {
6686 new_mapping->table_usecount = 1;
6687 } else {
6688 new_mapping->table_usecount = 0;
6689 }
6690
6691 LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6692
6693 if (allocated_mapping) {
6694 *allocated_mapping = TRUE;
6695 }
6696
6697 local_id = new_mapping->id;
6698 }
6699
6700 return local_id;
6701 }
6702
6703 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6704 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6705 {
6706 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6707
6708 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6709
6710 if (removed_mapping) {
6711 *removed_mapping = FALSE;
6712 }
6713
6714 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6715 if (existing_mapping != NULL) {
6716 if (uuid_policy_table) {
6717 existing_mapping->table_usecount--;
6718 }
6719 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6720 LIST_REMOVE(existing_mapping, chain);
6721 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6722 if (removed_mapping) {
6723 *removed_mapping = TRUE;
6724 }
6725 }
6726 return TRUE;
6727 }
6728
6729 return FALSE;
6730 }
6731
6732 #define NECP_NULL_AGENT_ID 1
6733 #define NECP_FIRST_VALID_AGENT_UUID_ID 2
6734 #define NECP_FIRST_VALID_AGENT_TYPE_ID UINT16_MAX
6735
6736 static bool
necp_agent_id_is_uuid(u_int32_t agent_id)6737 necp_agent_id_is_uuid(u_int32_t agent_id)
6738 {
6739 return agent_id < NECP_FIRST_VALID_AGENT_TYPE_ID;
6740 }
6741
6742 static u_int32_t
necp_get_new_agent_id(bool uuid)6743 necp_get_new_agent_id(bool uuid)
6744 {
6745 static u_int32_t necp_last_agent_id = 0;
6746 static u_int32_t necp_last_agent_type_id = 0;
6747
6748 u_int32_t newid = 0;
6749
6750 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6751
6752 if (uuid) {
6753 bool wrapped = FALSE;
6754 do {
6755 necp_last_agent_id++;
6756 if (necp_last_agent_id < NECP_FIRST_VALID_AGENT_UUID_ID ||
6757 necp_last_agent_id >= NECP_FIRST_VALID_AGENT_TYPE_ID) {
6758 if (wrapped) {
6759 // Already wrapped, give up
6760 NECPLOG0(LOG_ERR, "Failed to find a free agent UUID ID.\n");
6761 return NECP_NULL_AGENT_ID;
6762 }
6763 necp_last_agent_id = NECP_FIRST_VALID_AGENT_UUID_ID;
6764 wrapped = TRUE;
6765 }
6766 newid = necp_last_agent_id;
6767 } while (necp_uuid_lookup_uuid_with_agent_id_locked(newid) != NULL); // If already used, keep trying
6768 } else {
6769 bool wrapped = FALSE;
6770 do {
6771 necp_last_agent_type_id++;
6772 if (necp_last_agent_type_id < NECP_FIRST_VALID_AGENT_TYPE_ID) {
6773 if (wrapped) {
6774 // Already wrapped, give up
6775 NECPLOG0(LOG_ERR, "Failed to find a free agent type ID.\n");
6776 return NECP_NULL_AGENT_ID;
6777 }
6778 necp_last_agent_type_id = NECP_FIRST_VALID_AGENT_TYPE_ID;
6779 wrapped = TRUE;
6780 }
6781 newid = necp_last_agent_type_id;
6782 } while (necp_lookup_agent_type_with_id_locked(newid) != NULL); // If already used, keep trying
6783 }
6784
6785 if (newid == NECP_NULL_AGENT_ID) {
6786 NECPLOG0(LOG_ERR, "Allocate agent ID failed.\n");
6787 return NECP_NULL_AGENT_ID;
6788 }
6789
6790 return newid;
6791 }
6792
6793 static struct necp_uuid_id_mapping *
necp_uuid_get_null_agent_id_mapping(void)6794 necp_uuid_get_null_agent_id_mapping(void)
6795 {
6796 static struct necp_uuid_id_mapping null_mapping;
6797 uuid_clear(null_mapping.uuid);
6798 null_mapping.id = NECP_NULL_AGENT_ID;
6799
6800 return &null_mapping;
6801 }
6802
6803 static struct necp_uuid_id_mapping *
necp_uuid_lookup_agent_id_with_uuid_locked(uuid_t uuid)6804 necp_uuid_lookup_agent_id_with_uuid_locked(uuid_t uuid)
6805 {
6806 struct necp_uuid_id_mapping *searchentry = NULL;
6807 struct necp_uuid_id_mapping *foundentry = NULL;
6808
6809 if (uuid_is_null(uuid)) {
6810 return necp_uuid_get_null_agent_id_mapping();
6811 }
6812
6813 LIST_FOREACH(searchentry, &necp_agent_uuid_id_list, chain) {
6814 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6815 foundentry = searchentry;
6816 break;
6817 }
6818 }
6819
6820 return foundentry;
6821 }
6822
6823 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_agent_id_locked(u_int32_t agent_id)6824 necp_uuid_lookup_uuid_with_agent_id_locked(u_int32_t agent_id)
6825 {
6826 struct necp_uuid_id_mapping *searchentry = NULL;
6827 struct necp_uuid_id_mapping *foundentry = NULL;
6828
6829 if (agent_id == NECP_NULL_AGENT_ID) {
6830 return necp_uuid_get_null_agent_id_mapping();
6831 }
6832
6833 LIST_FOREACH(searchentry, &necp_agent_uuid_id_list, chain) {
6834 if (searchentry->id == agent_id) {
6835 foundentry = searchentry;
6836 break;
6837 }
6838 }
6839
6840 return foundentry;
6841 }
6842
6843 static u_int32_t
necp_create_agent_uuid_id_mapping(uuid_t uuid)6844 necp_create_agent_uuid_id_mapping(uuid_t uuid)
6845 {
6846 u_int32_t agent_id = 0;
6847 struct necp_uuid_id_mapping *existing_mapping = NULL;
6848
6849 if (uuid_is_null(uuid)) {
6850 return NECP_NULL_AGENT_ID;
6851 }
6852
6853 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6854
6855 existing_mapping = necp_uuid_lookup_agent_id_with_uuid_locked(uuid);
6856 if (existing_mapping != NULL) {
6857 agent_id = existing_mapping->id;
6858 os_ref_retain_locked(&existing_mapping->refcount);
6859 } else {
6860 struct necp_uuid_id_mapping *new_mapping = NULL;
6861 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6862 Z_WAITOK | Z_NOFAIL);
6863 uuid_copy(new_mapping->uuid, uuid);
6864 new_mapping->id = necp_get_new_agent_id(true);
6865 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6866
6867 LIST_INSERT_HEAD(&necp_agent_uuid_id_list, new_mapping, chain);
6868
6869 agent_id = new_mapping->id;
6870 }
6871
6872 return agent_id;
6873 }
6874
6875 static bool
necp_remove_agent_uuid_id_mapping(uuid_t uuid)6876 necp_remove_agent_uuid_id_mapping(uuid_t uuid)
6877 {
6878 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6879
6880 if (uuid_is_null(uuid)) {
6881 return TRUE;
6882 }
6883
6884 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6885
6886 existing_mapping = necp_uuid_lookup_agent_id_with_uuid_locked(uuid);
6887 if (existing_mapping != NULL) {
6888 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6889 LIST_REMOVE(existing_mapping, chain);
6890 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6891 }
6892 return TRUE;
6893 }
6894
6895 return FALSE;
6896 }
6897
6898 static bool
necp_remove_agent_uuid_id_mapping_with_agent_id(u_int32_t agent_id)6899 necp_remove_agent_uuid_id_mapping_with_agent_id(u_int32_t agent_id)
6900 {
6901 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6902
6903 if (agent_id == 0) {
6904 return TRUE;
6905 }
6906
6907 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6908
6909 existing_mapping = necp_uuid_lookup_uuid_with_agent_id_locked(agent_id);
6910 if (existing_mapping != NULL) {
6911 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6912 LIST_REMOVE(existing_mapping, chain);
6913 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6914 }
6915 return TRUE;
6916 }
6917
6918 return FALSE;
6919 }
6920
6921 static struct necp_agent_type_id_mapping *
necp_lookup_agent_type_to_id_locked(struct necp_policy_condition_agent_type * agent_type)6922 necp_lookup_agent_type_to_id_locked(struct necp_policy_condition_agent_type *agent_type)
6923 {
6924 struct necp_agent_type_id_mapping *searchentry = NULL;
6925 struct necp_agent_type_id_mapping *foundentry = NULL;
6926
6927 LIST_FOREACH(searchentry, &necp_agent_type_id_list, chain) {
6928 if (strlcmp(searchentry->agent_type.agent_domain, __unsafe_null_terminated_from_indexable(agent_type->agent_domain), NETAGENT_DOMAINSIZE) == 0 &&
6929 strlcmp(searchentry->agent_type.agent_type, __unsafe_null_terminated_from_indexable(agent_type->agent_type), NETAGENT_TYPESIZE) == 0) {
6930 foundentry = searchentry;
6931 break;
6932 }
6933 }
6934
6935 return foundentry;
6936 }
6937
6938 static struct necp_agent_type_id_mapping *
necp_lookup_agent_type_with_id_locked(u_int32_t agent_id)6939 necp_lookup_agent_type_with_id_locked(u_int32_t agent_id)
6940 {
6941 struct necp_agent_type_id_mapping *searchentry = NULL;
6942 struct necp_agent_type_id_mapping *foundentry = NULL;
6943
6944 LIST_FOREACH(searchentry, &necp_agent_type_id_list, chain) {
6945 if (searchentry->id == agent_id) {
6946 foundentry = searchentry;
6947 break;
6948 }
6949 }
6950
6951 return foundentry;
6952 }
6953
6954 static u_int32_t
necp_create_agent_type_to_id_mapping(struct necp_policy_condition_agent_type * agent_type)6955 necp_create_agent_type_to_id_mapping(struct necp_policy_condition_agent_type *agent_type)
6956 {
6957 u_int32_t agent_type_id = 0;
6958 struct necp_agent_type_id_mapping *existing_mapping = NULL;
6959
6960 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6961
6962 existing_mapping = necp_lookup_agent_type_to_id_locked(agent_type);
6963 if (existing_mapping != NULL) {
6964 agent_type_id = existing_mapping->id;
6965 os_ref_retain_locked(&existing_mapping->refcount);
6966 } else {
6967 struct necp_agent_type_id_mapping * __single new_mapping = NULL;
6968 new_mapping = kalloc_type(struct necp_agent_type_id_mapping,
6969 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6970 strlcpy(new_mapping->agent_type.agent_domain, __unsafe_null_terminated_from_indexable(agent_type->agent_domain), NETAGENT_DOMAINSIZE);
6971 strlcpy(new_mapping->agent_type.agent_type, __unsafe_null_terminated_from_indexable(agent_type->agent_type), NETAGENT_TYPESIZE);
6972 new_mapping->id = necp_get_new_agent_id(false);
6973 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6974 LIST_INSERT_HEAD(&necp_agent_type_id_list, new_mapping, chain);
6975 agent_type_id = new_mapping->id;
6976 }
6977 return agent_type_id;
6978 }
6979
6980 static bool
necp_remove_agent_type_to_id_mapping(u_int32_t agent_type_id)6981 necp_remove_agent_type_to_id_mapping(u_int32_t agent_type_id)
6982 {
6983 struct necp_agent_type_id_mapping * __single existing_mapping = NULL;
6984
6985 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6986
6987 existing_mapping = necp_lookup_agent_type_with_id_locked(agent_type_id);
6988 if (existing_mapping != NULL) {
6989 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6990 LIST_REMOVE(existing_mapping, chain);
6991 kfree_type(struct necp_agent_type_id_mapping, existing_mapping);
6992 }
6993 return true;
6994 }
6995
6996 return false;
6997 }
6998
6999 static bool
necp_kernel_socket_policies_update_uuid_table(void)7000 necp_kernel_socket_policies_update_uuid_table(void)
7001 {
7002 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7003
7004 if (necp_uuid_app_id_mappings_dirty) {
7005 uuid_t dummy_uuid = {};
7006 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
7007 NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
7008 return FALSE;
7009 }
7010
7011 if (necp_num_uuid_app_id_mappings > 0) {
7012 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
7013 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--) {
7014 struct necp_uuid_id_mapping *mapping = NULL;
7015 LIST_FOREACH(mapping, uuid_list_head, chain) {
7016 if (mapping->table_usecount > 0 &&
7017 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
7018 NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
7019 }
7020 }
7021 }
7022 }
7023
7024 necp_uuid_app_id_mappings_dirty = FALSE;
7025 }
7026
7027 return TRUE;
7028 }
7029
7030 #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)
7031 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)7032 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)
7033 {
7034 struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
7035 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7036
7037 new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
7038 new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
7039 new_kernel_policy->suborder = suborder;
7040 new_kernel_policy->order = order;
7041 new_kernel_policy->session_order = session_order;
7042 new_kernel_policy->session_pid = session_pid;
7043
7044 // Sanitize condition mask
7045 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
7046 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
7047 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
7048 }
7049 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
7050 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
7051 }
7052 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
7053 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
7054 }
7055 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
7056 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
7057 }
7058 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
7059
7060 // Set condition values
7061 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
7062 new_kernel_policy->cond_policy_id = cond_policy_id;
7063 }
7064 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
7065 if (cond_bound_interface) {
7066 ifnet_reference(cond_bound_interface);
7067 }
7068 new_kernel_policy->cond_bound_interface = cond_bound_interface;
7069 }
7070 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
7071 new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
7072 }
7073 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
7074 new_kernel_policy->cond_protocol = cond_protocol;
7075 }
7076 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7077 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
7078 }
7079 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7080 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
7081 }
7082 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7083 new_kernel_policy->cond_local_prefix = cond_local_prefix;
7084 }
7085 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7086 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
7087 }
7088 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7089 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
7090 }
7091 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7092 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
7093 }
7094 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
7095 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
7096 }
7097 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7098 new_kernel_policy->cond_scheme_port = cond_scheme_port;
7099 }
7100 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
7101 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
7102 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
7103 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
7104 }
7105 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
7106 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
7107 }
7108
7109 new_kernel_policy->result = result;
7110 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
7111
7112 if (necp_debug) {
7113 NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
7114 }
7115 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
7116
7117 return new_kernel_policy ? new_kernel_policy->id : 0;
7118 }
7119
7120 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)7121 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
7122 {
7123 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7124 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7125
7126 if (policy_id == 0) {
7127 return NULL;
7128 }
7129
7130 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
7131 if (kernel_policy->id == policy_id) {
7132 return kernel_policy;
7133 }
7134 }
7135
7136 return NULL;
7137 }
7138
7139 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)7140 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
7141 {
7142 struct necp_kernel_ip_output_policy * __single policy = NULL;
7143
7144 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7145
7146 policy = necp_kernel_ip_output_policy_find(policy_id);
7147 if (policy) {
7148 LIST_REMOVE(policy, chain);
7149
7150 if (policy->cond_bound_interface) {
7151 ifnet_release(policy->cond_bound_interface);
7152 policy->cond_bound_interface = NULL;
7153 }
7154
7155 zfree(necp_ip_policy_zone, policy);
7156 return TRUE;
7157 }
7158
7159 return FALSE;
7160 }
7161
7162 static void
necp_kernel_ip_output_policies_dump_all(void)7163 necp_kernel_ip_output_policies_dump_all(void)
7164 {
7165 if (necp_debug) {
7166 struct necp_kernel_ip_output_policy *policy = NULL;
7167 int policy_i;
7168 int id_i;
7169 char result_string[MAX_RESULT_STRING_LEN];
7170 char proc_name_string[MAXCOMLEN + 1];
7171 memset(result_string, 0, MAX_RESULT_STRING_LEN);
7172 memset(proc_name_string, 0, MAXCOMLEN + 1);
7173
7174 NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
7175 NECPLOG0(LOG_DEBUG, "-----------\n");
7176 for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
7177 NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
7178 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++) {
7179 policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
7180 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
7181 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));
7182 }
7183 NECPLOG0(LOG_DEBUG, "-----------\n");
7184 }
7185 }
7186 }
7187
7188 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)7189 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
7190 {
7191 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7192 if (upper_policy->session_order != lower_policy->session_order) {
7193 // A skip cannot override a policy of a different session
7194 return FALSE;
7195 } else {
7196 if (upper_policy->result_parameter.skip_policy_order == 0 ||
7197 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
7198 // This policy is beyond the skip
7199 return FALSE;
7200 } else {
7201 // This policy is inside the skip
7202 return TRUE;
7203 }
7204 }
7205 }
7206
7207 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
7208 return TRUE;
7209 }
7210
7211 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)7212 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)
7213 {
7214 bool can_skip = FALSE;
7215 u_int32_t highest_skip_session_order = 0;
7216 u_int32_t highest_skip_order = 0;
7217 int i;
7218 for (i = 0; i < valid_indices; i++) {
7219 struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
7220
7221 // For policies in a skip window, we can't mark conflicting policies as unnecessary
7222 if (can_skip) {
7223 if (highest_skip_session_order != compared_policy->session_order ||
7224 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
7225 // If we've moved on to the next session, or passed the skip window
7226 highest_skip_session_order = 0;
7227 highest_skip_order = 0;
7228 can_skip = FALSE;
7229 } else {
7230 // If this policy is also a skip, in can increase the skip window
7231 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7232 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
7233 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7234 }
7235 }
7236 continue;
7237 }
7238 }
7239
7240 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7241 // This policy is a skip. Set the skip window accordingly
7242 can_skip = TRUE;
7243 highest_skip_session_order = compared_policy->session_order;
7244 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7245 }
7246
7247 // The result of the compared policy must be able to block out this policy result
7248 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
7249 continue;
7250 }
7251
7252 // If new policy matches All Interfaces, compared policy must also
7253 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
7254 continue;
7255 }
7256
7257 // If new policy matches Local Networks, compared policy must also
7258 if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
7259 continue;
7260 }
7261
7262 // Default makes lower policies unnecessary always
7263 if (compared_policy->condition_mask == 0) {
7264 return TRUE;
7265 }
7266
7267 // Compared must be more general than policy, and include only conditions within policy
7268 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
7269 continue;
7270 }
7271
7272 // Negative conditions must match for the overlapping conditions
7273 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
7274 continue;
7275 }
7276
7277 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
7278 compared_policy->cond_policy_id != policy->cond_policy_id) {
7279 continue;
7280 }
7281
7282 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
7283 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
7284 continue;
7285 }
7286
7287 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
7288 compared_policy->cond_protocol != policy->cond_protocol) {
7289 continue;
7290 }
7291
7292 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7293 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7294 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))) {
7295 continue;
7296 }
7297 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7298 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
7299 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
7300 continue;
7301 }
7302 }
7303 }
7304
7305 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7306 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7307 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))) {
7308 continue;
7309 }
7310 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7311 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
7312 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
7313 continue;
7314 }
7315 }
7316 }
7317
7318 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
7319 compared_policy->cond_scheme_port != policy->cond_scheme_port) {
7320 continue;
7321 }
7322
7323 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
7324 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
7325 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
7326 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
7327 continue;
7328 }
7329
7330 return TRUE;
7331 }
7332
7333 return FALSE;
7334 }
7335
7336 static bool
necp_kernel_ip_output_policies_reprocess(void)7337 necp_kernel_ip_output_policies_reprocess(void)
7338 {
7339 int i;
7340 int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
7341 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7342
7343 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7344
7345 // Reset mask to 0
7346 necp_kernel_ip_output_policies_condition_mask = 0;
7347 necp_kernel_ip_output_policies_count = 0;
7348 necp_kernel_ip_output_policies_non_id_count = 0;
7349
7350 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7351 if (necp_kernel_ip_output_policies_map[i] != NULL) {
7352 kfree_type(struct necp_kernel_ip_output_policy *,
7353 necp_kernel_ip_output_policies_map_counts[i] + 1,
7354 necp_kernel_ip_output_policies_map[i]);
7355 necp_kernel_ip_output_policies_map[i] = NULL;
7356 }
7357
7358 // Init counts
7359 necp_kernel_ip_output_policies_map_counts[i] = 0;
7360 }
7361
7362 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7363 // Update mask
7364 necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
7365 necp_kernel_ip_output_policies_count++;
7366
7367 /* Update bucket counts:
7368 * Non-id and SKIP policies will be added to all buckets
7369 * Add local networks policy to all buckets for incoming IP
7370 */
7371 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7372 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7373 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7374 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7375 necp_kernel_ip_output_policies_map_counts[i]++;
7376 }
7377 }
7378 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
7379 necp_kernel_ip_output_policies_non_id_count++;
7380 } else {
7381 necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
7382 }
7383 }
7384
7385 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7386 if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
7387 // Allocate a NULL-terminated array of policy pointers for each bucket
7388 necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
7389 necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
7390 if (necp_kernel_ip_output_policies_map[i] == NULL) {
7391 goto fail;
7392 }
7393 }
7394 bucket_current_free_index[i] = 0;
7395 }
7396
7397 u_int32_t current_session_order = 0;
7398 u_int32_t current_session_last_non_skip_policy = 0;
7399
7400 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7401 // For each new session, find the last non-skip policy. We can
7402 // avoid adding any skip policies that don't actually skip over
7403 // any non-skip policies.
7404 if (current_session_order != kernel_policy->session_order) {
7405 current_session_order = kernel_policy->session_order;
7406 current_session_last_non_skip_policy = 0;
7407
7408 struct necp_kernel_ip_output_policy *inner_policy = NULL;
7409 LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
7410 if (inner_policy->session_order < current_session_order) {
7411 continue;
7412 }
7413 if (inner_policy->session_order > current_session_order) {
7414 break;
7415 }
7416 if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7417 continue;
7418 }
7419
7420 current_session_last_non_skip_policy = inner_policy->order;
7421 }
7422 }
7423
7424 if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7425 if (current_session_last_non_skip_policy == 0) {
7426 // No useful policies to skip over, don't add
7427 continue;
7428 }
7429 if (kernel_policy->order >= current_session_last_non_skip_policy) {
7430 // Skip policy is after the last useful policy, don't add
7431 continue;
7432 }
7433 }
7434
7435 // Insert pointers into map
7436 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7437 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7438 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7439 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7440 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])) {
7441 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7442 bucket_current_free_index[i]++;
7443 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7444 }
7445 }
7446 } else {
7447 i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7448 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])) {
7449 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7450 bucket_current_free_index[i]++;
7451 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7452 }
7453 }
7454 }
7455
7456 if (bucket_current_free_index[0] == 0) {
7457 // No non-id policies were actually added
7458 necp_kernel_ip_output_policies_non_id_count = 0;
7459
7460 // Also check if no policies at all were added
7461 bool policies_added = FALSE;
7462 for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7463 if (bucket_current_free_index[i] != 0) {
7464 policies_added = TRUE;
7465 break;
7466 }
7467 }
7468 if (!policies_added) {
7469 necp_kernel_ip_output_policies_condition_mask = 0;
7470 necp_kernel_ip_output_policies_count = 0;
7471 }
7472 }
7473
7474 necp_kernel_ip_output_policies_dump_all();
7475 return TRUE;
7476
7477 fail:
7478 // Free memory, reset mask to 0
7479 necp_kernel_ip_output_policies_condition_mask = 0;
7480 necp_kernel_ip_output_policies_count = 0;
7481 necp_kernel_ip_output_policies_non_id_count = 0;
7482 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7483 if (necp_kernel_ip_output_policies_map[i] != NULL) {
7484 kfree_type(struct necp_kernel_ip_output_policy *,
7485 necp_kernel_ip_output_policies_map_counts[i] + 1,
7486 necp_kernel_ip_output_policies_map[i]);
7487 necp_kernel_ip_output_policies_map[i] = NULL;
7488 }
7489 }
7490 return FALSE;
7491 }
7492
7493 // Outbound Policy Matching
7494 // ---------------------
7495 struct substring {
7496 size_t length;
7497 char * __sized_by(length) string;
7498 };
7499
7500 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7501 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7502 {
7503 struct substring sub = {};
7504 char * __indexable ptr = string;
7505 size_t len = string ? length : 0;
7506
7507 while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7508 ptr++;
7509 len--;
7510 }
7511
7512 while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7513 len--;
7514 }
7515
7516 sub.string = ptr;
7517 sub.length = len;
7518 return sub;
7519 }
7520
7521 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7522 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7523 {
7524 size_t trimmed_domain_length = 0;
7525 char *trimmed_domain = NULL;
7526 struct substring sub = necp_trim_dots_and_stars(string, length);
7527
7528 trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7529 trimmed_domain_length = sub.length + 1;
7530 if (trimmed_domain == NULL) {
7531 return NULL;
7532 }
7533
7534 strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7535 trimmed_domain[sub.length] = 0;
7536
7537 return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7538 }
7539
7540 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7541 necp_count_dots(char * __sized_by(length)string, size_t length)
7542 {
7543 int dot_count = 0;
7544 size_t i = 0;
7545
7546 for (i = 0; i < length; i++) {
7547 if (string[i] == '.') {
7548 dot_count++;
7549 }
7550 }
7551
7552 return dot_count;
7553 }
7554
7555 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7556 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7557 {
7558 if (parent.length <= suffix.length) {
7559 return FALSE;
7560 }
7561
7562 size_t length_difference = (parent.length - suffix.length);
7563
7564 if (require_dot_before_suffix) {
7565 if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7566 return FALSE;
7567 }
7568 }
7569
7570 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7571 return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7572 }
7573
7574 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)7575 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7576 {
7577 if (hostname_substring.string == NULL || domain == NULL) {
7578 return hostname_substring.string == domain;
7579 }
7580
7581 struct substring domain_substring;
7582 domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7583 domain_substring.length = strlen(domain);
7584
7585 if (hostname_dot_count == domain_dot_count) {
7586 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7587 if (hostname_substring.length == domain_substring.length &&
7588 strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7589 return TRUE;
7590 }
7591 } else if (domain_dot_count < hostname_dot_count) {
7592 if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7593 return TRUE;
7594 }
7595 }
7596
7597 return FALSE;
7598 }
7599
7600 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7601 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7602 {
7603 if (hostname_string == NULL ||
7604 domain_string == NULL) {
7605 return false;
7606 }
7607
7608 struct substring hostname_substring;
7609 hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7610 hostname_substring.length = strlen(hostname_string);
7611
7612 return necp_hostname_matches_domain(hostname_substring,
7613 necp_count_dots(hostname_substring.string, hostname_substring.length),
7614 domain_string,
7615 necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7616 }
7617
7618 #define NECP_MAX_STRING_LEN 1024
7619
7620 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7621 necp_copy_string(char * __sized_by(length)string, size_t length)
7622 {
7623 size_t copied_string_length = 0;
7624 char * __sized_by(copied_string_length) copied_string = NULL;
7625
7626 if (length > NECP_MAX_STRING_LEN) {
7627 return NULL;
7628 }
7629
7630 copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7631 copied_string_length = length + 1;
7632 if (copied_string == NULL) {
7633 return NULL;
7634 }
7635
7636 memcpy(copied_string, string, length);
7637 copied_string[length] = 0;
7638
7639 return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7640 }
7641
7642 static u_int32_t
necp_get_primary_direct_interface_index(void)7643 necp_get_primary_direct_interface_index(void)
7644 {
7645 u_int32_t interface_index = IFSCOPE_NONE;
7646
7647 ifnet_head_lock_shared();
7648 struct ifnet *ordered_interface = NULL;
7649 TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7650 const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7651 if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7652 functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7653 // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7654 interface_index = ordered_interface->if_index;
7655 break;
7656 }
7657 }
7658 ifnet_head_done();
7659
7660 return interface_index;
7661 }
7662
7663 static inline bool
necp_task_has_match_entitlement(task_t task)7664 necp_task_has_match_entitlement(task_t task)
7665 {
7666 return task != NULL &&
7667 (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7668 IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7669 }
7670
7671 // Loopback traffic from certain entitled process will be dropped
7672 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7673 necp_task_has_loopback_drop_entitlement(task_t task)
7674 {
7675 bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7676 if (drop) {
7677 necp_drop_loopback_count++;
7678 }
7679 return drop;
7680 }
7681
7682 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7683 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7684 {
7685 coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7686
7687 if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7688 // No parent, nothing to do
7689 return;
7690 }
7691
7692 task_t __single lead_task = coalition_get_leader(coal);
7693 if (lead_task != NULL) {
7694 info->is_entitled = necp_task_has_match_entitlement(lead_task);
7695 task_deallocate(lead_task);
7696 }
7697 }
7698
7699 // Some processes, due to particular entitlements, require using an NECP client to
7700 // access networking. Returns true if the result should be a Drop.
7701 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7702 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7703 {
7704 if (necp_is_platform_binary(proc)) {
7705 // This check is currently for the "on-demand-install-capable"
7706 // entitlement, which by definition cannot be a built-in platform
7707 // binary.
7708 return false;
7709 }
7710
7711 task_t __single task = proc_task(proc ? proc : current_proc());
7712
7713 if (!info->has_client &&
7714 task != NULL &&
7715 IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7716 // Drop connections that don't use NECP clients and have the
7717 // com.apple.developer.on-demand-install-capable entitlement.
7718 // This effectively restricts those processes to only using
7719 // an NECP-aware path for networking.
7720 return true;
7721 } else {
7722 return false;
7723 }
7724 }
7725
7726 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7727 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7728 {
7729 if (!necp_restrict_multicast || proc == NULL) {
7730 return false;
7731 }
7732
7733 // Check for multicast/broadcast here
7734 if (info->remote_addr.sa.sa_family == AF_INET) {
7735 if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7736 info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7737 return false;
7738 }
7739 } else if (info->remote_addr.sa.sa_family == AF_INET6) {
7740 if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7741 return false;
7742 }
7743 } else {
7744 // Not IPv4/IPv6
7745 return false;
7746 }
7747
7748 if (necp_is_platform_binary(proc)) {
7749 return false;
7750 }
7751
7752 const uint32_t platform = proc_platform(proc);
7753 const uint32_t sdk = proc_sdk(proc);
7754
7755 // Enforce for iOS, linked on or after version 14
7756 // If the caller set `check_minor_version`, only enforce starting at 14.5
7757 if ((platform != PLATFORM_IOS ||
7758 sdk == 0 ||
7759 (sdk >> 16) < 14 ||
7760 (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7761 return false;
7762 }
7763
7764 // Allow entitled processes to use multicast
7765 task_t __single task = proc_task(proc);
7766 if (task != NULL &&
7767 IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7768 return false;
7769 }
7770
7771 const uint32_t min_sdk = proc_min_sdk(proc);
7772 NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7773
7774 return true;
7775 }
7776
7777 #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)
7778 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)7779 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)
7780 {
7781 memset(info, 0, sizeof(struct necp_socket_info));
7782
7783 info->pid = pid;
7784 info->pid_version = pid_version;
7785 info->uid = uid;
7786 info->real_uid = real_uid;
7787 info->protocol = protocol;
7788 info->bound_interface_index = bound_interface_index;
7789 info->traffic_class = traffic_class;
7790 info->has_client = has_client;
7791 info->has_system_signed_result = has_system_signed_result;
7792 info->drop_order = drop_order;
7793 info->client_flags = client_flags;
7794 info->is_loopback = is_loopback;
7795 info->is_delegated = is_delegated;
7796
7797 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7798 info->bound_interface_index != IFSCOPE_NONE) {
7799 ifnet_head_lock_shared();
7800 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7801 if (interface != NULL) {
7802 info->bound_interface_flags = interface->if_flags;
7803 info->bound_interface_eflags = interface->if_eflags;
7804 info->bound_interface_xflags = interface->if_xflags;
7805 }
7806 ifnet_head_done();
7807 }
7808
7809 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7810 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7811 if (existing_mapping) {
7812 info->application_id = existing_mapping->id;
7813 }
7814 }
7815
7816 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7817 if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7818 info->real_application_id = info->application_id;
7819 } else {
7820 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7821 if (existing_mapping) {
7822 info->real_application_id = existing_mapping->id;
7823 }
7824 }
7825 }
7826
7827 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7828 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7829 if (existing_mapping != NULL) {
7830 info->real_application_id = info->application_id;
7831 info->application_id = existing_mapping->id;
7832 info->used_responsible_pid = true;
7833 }
7834 }
7835
7836 if (info->used_responsible_pid) {
7837 proc = responsible_proc;
7838 }
7839
7840 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7841 info->is_entitled = necp_task_has_match_entitlement(task);
7842 if (!info->is_entitled) {
7843 // Task does not have entitlement, check the parent task
7844 necp_get_parent_is_entitled(task, info);
7845 }
7846 }
7847
7848 if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7849 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7850 if (necp_is_platform_binary(proc)) {
7851 info->is_platform_binary = true;
7852 } else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7853 info->is_platform_binary = true;
7854 info->used_responsible_pid = true;
7855 } else {
7856 info->is_platform_binary = false;
7857 }
7858 }
7859
7860 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7861 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7862 }
7863
7864 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7865 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7866 if (existing_mapping) {
7867 info->account_id = existing_mapping->id;
7868 }
7869 }
7870
7871 if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7872 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7873 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7874 info->domain = domain;
7875 }
7876
7877 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7878 info->url = url;
7879 }
7880
7881 if ((necp_data_tracing_level && necp_data_tracing_port) ||
7882 necp_restrict_multicast ||
7883 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7884 if (local_addr && local_addr->sa.sa_len > 0) {
7885 SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7886 if (local_port != 0) {
7887 info->local_addr.sin6.sin6_port = local_port;
7888 }
7889 } else {
7890 if (remote_addr && remote_addr->sa.sa_len > 0) {
7891 info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7892 info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7893 } else {
7894 info->local_addr.sin6.sin6_family = AF_INET6;
7895 info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7896 }
7897 if (local_port != 0) {
7898 info->local_addr.sin6.sin6_port = local_port;
7899 }
7900 }
7901 if (remote_addr && remote_addr->sa.sa_len > 0) {
7902 SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7903 if (remote_port != 0) {
7904 info->remote_addr.sin6.sin6_port = remote_port;
7905 }
7906 } else if (remote_port != 0) {
7907 info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7908 info->remote_addr.sin6.sin6_family = AF_INET6;
7909 info->remote_addr.sin6.sin6_port = remote_port;
7910 }
7911 }
7912
7913 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7914 info->scheme_port = scheme_port;
7915 }
7916 }
7917
7918 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7919 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7920 {
7921 struct kev_netpolicy_ifdenied ev_ifdenied;
7922
7923 bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7924
7925 ev_ifdenied.ev_data.epid = pid;
7926 uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7927 ev_ifdenied.ev_if_functional_type = if_functional_type;
7928
7929 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7930 }
7931
7932 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7933 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7934 {
7935 struct kev_netpolicy_netdenied ev_netdenied = {};
7936
7937 bzero(&ev_netdenied, sizeof(ev_netdenied));
7938
7939 ev_netdenied.ev_data.epid = pid;
7940 uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7941 ev_netdenied.ev_network_type = network_type;
7942
7943 netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7944 }
7945
7946 extern char *proc_name_address(void *p);
7947
7948 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7949 if (!has_checked_delegation_entitlement) { \
7950 has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7951 has_checked_delegation_entitlement = TRUE; \
7952 } \
7953 if (!has_delegation_entitlement) { \
7954 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7955 proc_name_address(_p), proc_pid(_p), _d); \
7956 break; \
7957 }
7958
7959 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)7960 necp_application_find_policy_match_internal(proc_t proc,
7961 u_int8_t * __sized_by(parameters_size)parameters,
7962 u_int32_t parameters_size,
7963 struct necp_aggregate_result *returned_result,
7964 u_int32_t *flags,
7965 u_int32_t *reason,
7966 u_int required_interface_index,
7967 const union necp_sockaddr_union *override_local_addr,
7968 const union necp_sockaddr_union *override_remote_addr,
7969 struct necp_client_endpoint *returned_v4_gateway,
7970 struct necp_client_endpoint *returned_v6_gateway,
7971 struct rtentry **returned_route, bool ignore_address,
7972 bool has_client,
7973 uuid_t *returned_override_euuid)
7974 {
7975 int error = 0;
7976 size_t offset = 0;
7977
7978 struct necp_kernel_socket_policy *matched_policy = NULL;
7979 struct necp_socket_info info = {};
7980 necp_kernel_policy_filter filter_control_unit = 0;
7981
7982 u_int64_t extended_client_flags = 0;
7983 u_int16_t protocol = 0;
7984 u_int32_t bound_interface_index = required_interface_index;
7985 u_int32_t traffic_class = 0;
7986 u_int32_t client_flags = 0;
7987 u_int16_t scheme_port = 0;
7988 union necp_sockaddr_union local_addr;
7989 union necp_sockaddr_union remote_addr;
7990 bool no_remote_addr = FALSE;
7991 u_int8_t remote_family = 0;
7992 bool no_local_addr = FALSE;
7993 u_int16_t local_port = 0;
7994 u_int16_t remote_port = 0;
7995 u_int32_t remote_endpoint_type = 0;
7996 bool remote_address_is_empty = false;
7997 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7998 bool is_delegated = false;
7999
8000 if (override_local_addr) {
8001 memcpy(&local_addr, override_local_addr, sizeof(local_addr));
8002 } else {
8003 memset(&local_addr, 0, sizeof(local_addr));
8004 }
8005 if (override_remote_addr) {
8006 memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
8007 } else {
8008 memset(&remote_addr, 0, sizeof(remote_addr));
8009 }
8010
8011 // Initialize UID, PID, and UUIDs to the current process
8012 uid_t uid = 0;
8013 uid_t real_uid = 0;
8014 kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
8015 if (cred != NULL) {
8016 uid = kauth_cred_getuid(cred);
8017 real_uid = uid;
8018 }
8019 task_t __single task = proc_task(proc);
8020 pid_t pid = proc_pid(proc);
8021 int32_t pid_version = proc_pidversion(proc);
8022 uuid_t application_uuid;
8023 uuid_clear(application_uuid);
8024 uuid_t real_application_uuid;
8025 uuid_clear(real_application_uuid);
8026 proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
8027 uuid_copy(application_uuid, real_application_uuid);
8028 uuid_t responsible_application_uuid;
8029 uuid_clear(responsible_application_uuid);
8030
8031 char *domain __null_terminated = NULL;
8032 char *url __null_terminated = NULL;
8033 char *account __null_terminated = NULL;
8034
8035 #define NECP_MAX_REQUIRED_AGENTS 16
8036 u_int32_t num_required_agent_types = 0;
8037 struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
8038 memset(&required_agent_types, 0, sizeof(required_agent_types));
8039
8040 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
8041 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
8042 memset(&netagent_ids, 0, sizeof(netagent_ids));
8043 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
8044 int netagent_cursor;
8045
8046 bool has_checked_delegation_entitlement = false;
8047 bool has_delegation_entitlement = false;
8048 bool has_system_signed_result = false;
8049
8050 proc_t responsible_proc = PROC_NULL;
8051 proc_t effective_proc = proc;
8052 bool release_eproc = false;
8053 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
8054
8055 u_int32_t flow_divert_aggregate_unit = 0;
8056
8057 if (returned_result == NULL) {
8058 if (cred != NULL) {
8059 kauth_cred_unref(&cred);
8060 }
8061 return EINVAL;
8062 }
8063
8064 if (returned_v4_gateway != NULL) {
8065 memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
8066 }
8067
8068 if (returned_v6_gateway != NULL) {
8069 memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
8070 }
8071
8072 if (returned_override_euuid != NULL) {
8073 uuid_clear(*returned_override_euuid);
8074 }
8075
8076 memset(returned_result, 0, sizeof(struct necp_aggregate_result));
8077
8078 u_int32_t drop_order = necp_process_drop_order(cred);
8079
8080 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
8081
8082 lck_rw_lock_shared(&necp_kernel_policy_lock);
8083 if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
8084 if (necp_drop_all_order > 0 || drop_order > 0) {
8085 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8086 lck_rw_done(&necp_kernel_policy_lock);
8087 if (cred != NULL) {
8088 kauth_cred_unref(&cred);
8089 }
8090 return 0;
8091 }
8092 }
8093 lck_rw_done(&necp_kernel_policy_lock);
8094
8095 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
8096 u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
8097 u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
8098
8099 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
8100 // If the length is larger than what can fit in the remaining parameters size, bail
8101 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
8102 break;
8103 }
8104
8105 if (length > 0) {
8106 u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
8107 if (value != NULL) {
8108 switch (type) {
8109 case NECP_CLIENT_PARAMETER_APPLICATION: {
8110 if (length >= sizeof(uuid_t)) {
8111 if (uuid_compare(application_uuid, value) == 0) {
8112 // No delegation
8113 break;
8114 }
8115
8116 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
8117
8118 is_delegated = true;
8119 uuid_copy(application_uuid, value);
8120 }
8121 break;
8122 }
8123 case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
8124 if (length >= sizeof(uuid_t)) {
8125 if (uuid_compare(real_application_uuid, value) == 0) {
8126 // No delegation
8127 break;
8128 }
8129
8130 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
8131
8132 is_delegated = true;
8133 uuid_copy(real_application_uuid, value);
8134 }
8135 break;
8136 }
8137 case NECP_CLIENT_PARAMETER_PID: {
8138 if (length >= sizeof(pid_t)) {
8139 if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
8140 // No delegation
8141 break;
8142 }
8143
8144 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
8145
8146 is_delegated = true;
8147 memcpy(&pid, value, sizeof(pid_t));
8148 }
8149 break;
8150 }
8151 case NECP_CLIENT_PARAMETER_UID: {
8152 if (length >= sizeof(uid_t)) {
8153 if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
8154 // No delegation
8155 break;
8156 }
8157
8158 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
8159
8160 is_delegated = true;
8161 memcpy(&uid, value, sizeof(uid_t));
8162 }
8163 break;
8164 }
8165 case NECP_CLIENT_PARAMETER_DOMAIN: {
8166 char *ptr = (char *)value;
8167 ptr[length - 1] = 0;
8168 domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8169 break;
8170 }
8171 case NECP_CLIENT_PARAMETER_URL: {
8172 char *ptr = (char *)value;
8173 ptr[length - 1] = 0;
8174 url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8175 break;
8176 }
8177 case NECP_CLIENT_PARAMETER_ACCOUNT: {
8178 char *ptr = (char *)value;
8179 ptr[length - 1] = 0;
8180 account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8181 break;
8182 }
8183 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
8184 if (length >= sizeof(u_int32_t)) {
8185 memcpy(&traffic_class, value, sizeof(u_int32_t));
8186 }
8187 break;
8188 }
8189 case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
8190 if (length >= sizeof(u_int16_t)) {
8191 memcpy(&protocol, value, sizeof(u_int16_t));
8192 } else if (length >= sizeof(u_int8_t)) {
8193 memcpy(&protocol, value, sizeof(u_int8_t));
8194 }
8195 break;
8196 }
8197 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
8198 if (length <= IFXNAMSIZ && length > 0) {
8199 ifnet_t __single bound_interface = NULL;
8200 char interface_name[IFXNAMSIZ];
8201 memcpy(interface_name, value, length);
8202 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
8203 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
8204 bound_interface_index = bound_interface->if_index;
8205 ifnet_release(bound_interface);
8206 }
8207 }
8208 break;
8209 }
8210 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
8211 if (ignore_address || override_local_addr) {
8212 break;
8213 }
8214
8215 if (length >= sizeof(struct necp_policy_condition_addr)) {
8216 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8217 if (necp_address_is_valid(&address_struct->address.sa)) {
8218 memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
8219 }
8220 }
8221 break;
8222 }
8223 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
8224 if (ignore_address || override_remote_addr) {
8225 break;
8226 }
8227
8228 if (length >= sizeof(struct necp_policy_condition_addr)) {
8229 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8230 if (necp_address_is_valid(&address_struct->address.sa)) {
8231 memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
8232 }
8233 }
8234 break;
8235 }
8236 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
8237 if (ignore_address || override_local_addr) {
8238 break;
8239 }
8240
8241 if (length >= sizeof(struct necp_client_endpoint)) {
8242 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8243 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
8244 endpoint->u.endpoint.endpoint_port != 0) {
8245 // Save port
8246 local_port = endpoint->u.endpoint.endpoint_port;
8247 }
8248 }
8249 break;
8250 }
8251 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
8252 if (ignore_address || override_remote_addr) {
8253 break;
8254 }
8255
8256 if (length >= sizeof(struct necp_client_endpoint)) {
8257 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8258 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
8259 remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
8260 if (endpoint->u.endpoint.endpoint_port != 0) {
8261 // Save port
8262 remote_port = endpoint->u.endpoint.endpoint_port;
8263 }
8264 } else if (necp_addr_is_empty(&endpoint->u.sa)) {
8265 remote_address_is_empty = true;
8266 }
8267 }
8268 break;
8269 }
8270 case NECP_CLIENT_PARAMETER_FLAGS: {
8271 if (length >= sizeof(client_flags)) {
8272 memcpy(&client_flags, value, sizeof(client_flags));
8273 }
8274 break;
8275 }
8276 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
8277 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
8278 if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8279 break;
8280 }
8281 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
8282 memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
8283 num_required_agent_types++;
8284 }
8285 break;
8286 }
8287 case NECP_CLIENT_PARAMETER_PREFER_AGENT: {
8288 if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8289 break;
8290 }
8291 if (length >= sizeof(uuid_t)) {
8292 if (netagent_get_agent_domain_and_type(value,
8293 required_agent_types[num_required_agent_types].netagent_domain,
8294 required_agent_types[num_required_agent_types].netagent_type)) {
8295 num_required_agent_types++;
8296 }
8297 }
8298 break;
8299 }
8300 case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
8301 if (length >= sizeof(scheme_port)) {
8302 memcpy(&scheme_port, value, sizeof(scheme_port));
8303 }
8304 break;
8305 }
8306 case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
8307 has_system_signed_result = true;
8308 struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
8309 if (length >= sizeof(struct necp_client_validatable)) {
8310 // Check for system-signed sign_type values
8311 if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
8312 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
8313 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
8314 has_system_signed_result = true;
8315 }
8316 }
8317 break;
8318 }
8319 case NECP_CLIENT_PARAMETER_EXTENDED_FLAGS: {
8320 if (length >= sizeof(extended_client_flags)) {
8321 memcpy(&extended_client_flags, value, sizeof(extended_client_flags));
8322 }
8323 break;
8324 }
8325 default: {
8326 break;
8327 }
8328 }
8329 }
8330 }
8331
8332 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
8333 }
8334
8335 // Check for loopback exception
8336 if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
8337 if (necp_task_has_loopback_drop_entitlement(task)) {
8338 // Disallow certain entitled processes to send loopback traffic
8339 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8340 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8341 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8342 if (cred != NULL) {
8343 kauth_cred_unref(&cred);
8344 }
8345 return 0;
8346 }
8347 if (necp_pass_loopback > 0) {
8348 bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
8349 }
8350 } else if (bound_interface_index != IFSCOPE_NONE) {
8351 // Check for inter-process exception
8352 struct sockaddr *dst = SA(&remote_addr.sa);
8353 if (dst->sa_family == AF_INET6) {
8354 struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
8355 if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
8356 ifnet_head_lock_shared();
8357 ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
8358 if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
8359 bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
8360 }
8361 ifnet_head_done();
8362 }
8363 }
8364 }
8365
8366 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
8367 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8368 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8369 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8370 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
8371 returned_result->routed_interface_index = lo_ifp->if_index;
8372 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8373 } else {
8374 returned_result->routed_interface_index = bound_interface_index;
8375 }
8376 if (cred != NULL) {
8377 kauth_cred_unref(&cred);
8378 }
8379 return 0;
8380 }
8381
8382 if (drop_order != 0) {
8383 if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
8384 client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
8385 ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
8386 // Allow listeners, inbound connections without remote addresses, and
8387 // application service connections to bypass the unentitled drop order,
8388 // to allow them to connect to application services (not directly over
8389 // physical networking interfaces)
8390 drop_order = 0;
8391 }
8392 }
8393
8394 if (proc_pid(effective_proc) != pid) {
8395 proc_t found_proc = proc_find(pid);
8396 if (found_proc != PROC_NULL) {
8397 effective_proc = found_proc;
8398 pid_version = proc_pidversion(effective_proc);
8399 release_eproc = true;
8400 }
8401 }
8402 #if defined(XNU_TARGET_OS_OSX)
8403 if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
8404 proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
8405 responsible_proc = proc_find(effective_proc->p_responsible_pid);
8406 }
8407 #endif /* defined(XNU_TARGET_OS_OSX) */
8408
8409 // Lock
8410 lck_rw_lock_shared(&necp_kernel_policy_lock);
8411
8412 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
8413 size_t route_rule_id_array_count = 0;
8414 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);
8415
8416 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
8417 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
8418
8419 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
8420 matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
8421 &info,
8422 &filter_control_unit,
8423 route_rule_id_array,
8424 &route_rule_id_array_count,
8425 MAX_AGGREGATE_ROUTE_RULES,
8426 netagent_ids,
8427 NECP_MAX_NETAGENTS,
8428 netagent_use_flags,
8429 NECP_MAX_NETAGENTS,
8430 required_agent_types,
8431 num_required_agent_types,
8432 info.used_responsible_pid ? responsible_proc : effective_proc,
8433 0,
8434 &skip_policy_id,
8435 NULL,
8436 &drop_dest_policy_result,
8437 &drop_all_bypass,
8438 &flow_divert_aggregate_unit,
8439 NULL,
8440 debug);
8441
8442 // Check for loopback exception again after the policy match
8443 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
8444 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
8445 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
8446 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8447 returned_result->filter_control_unit = 0;
8448 } else {
8449 returned_result->filter_control_unit = filter_control_unit;
8450 }
8451
8452 if (flow_divert_aggregate_unit > 0) {
8453 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8454 }
8455
8456 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8457 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8458 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8459 returned_result->routed_interface_index = lo_ifp->if_index;
8460 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8461 error = 0;
8462 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8463 goto done;
8464 }
8465
8466 if (matched_policy) {
8467 returned_result->policy_id = matched_policy->id;
8468 returned_result->skip_policy_id = skip_policy_id;
8469 returned_result->routing_result = matched_policy->result;
8470 memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8471 if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8472 uuid_copy(*returned_override_euuid, responsible_application_uuid);
8473 }
8474 } else {
8475 bool drop_all = false;
8476 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8477 // Mark socket as a drop if drop_all is set
8478 drop_all = true;
8479 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8480 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8481 }
8482 }
8483 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8484 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8485 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8486 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8487 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8488 } else {
8489 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8490 returned_result->skip_policy_id = skip_policy_id;
8491 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8492 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8493 }
8494 }
8495 if (necp_check_missing_client_drop(proc, &info) ||
8496 necp_check_restricted_multicast_drop(proc, &info, false)) {
8497 // Mark as drop
8498 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8499 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8500 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8501 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8502 }
8503 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8504 returned_result->filter_control_unit = 0;
8505 } else {
8506 returned_result->filter_control_unit = filter_control_unit;
8507 }
8508
8509 if (flow_divert_aggregate_unit > 0) {
8510 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8511 }
8512
8513 // Handle netagents
8514 size_t netagent_i = 0;
8515 size_t removed_netagent_type_i = 0;
8516 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8517 u_int32_t netagent_id = netagent_ids[netagent_cursor];
8518 if (netagent_id == 0) {
8519 continue;
8520 }
8521
8522 if (necp_agent_id_is_uuid(netagent_id)) {
8523 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
8524 if (mapping != NULL) {
8525 uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8526 returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8527 netagent_i++;
8528 }
8529 } else {
8530 struct necp_agent_type_id_mapping *mapping = necp_lookup_agent_type_with_id_locked(netagent_id);
8531 if (mapping != NULL && removed_netagent_type_i < NECP_MAX_REMOVE_NETAGENT_TYPES &&
8532 netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8533 memcpy(&returned_result->remove_netagent_types[removed_netagent_type_i], &mapping->agent_type, sizeof(mapping->agent_type));
8534 removed_netagent_type_i++;
8535 }
8536 }
8537
8538 // If the flags say to remove, clear the local copy
8539 if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8540 netagent_ids[netagent_cursor] = 0;
8541 }
8542 }
8543
8544 // Do routing evaluation
8545 u_int output_bound_interface = bound_interface_index;
8546 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8547 output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8548 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8549 output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8550 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8551 output_bound_interface = necp_get_primary_direct_interface_index();
8552 if (output_bound_interface == IFSCOPE_NONE) {
8553 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8554 } else {
8555 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8556 returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8557 }
8558 }
8559
8560 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8561 returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8562 if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8563 // Trigger the event that we dropped due to a local network policy
8564 #if defined(XNU_TARGET_OS_OSX)
8565 bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8566 necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8567 should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8568 NETPOLICY_NETWORKTYPE_LOCAL);
8569 #else
8570 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8571 #endif
8572 }
8573 if (reason != NULL) {
8574 *reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8575 }
8576 }
8577
8578 if (local_addr.sa.sa_len == 0 ||
8579 (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8580 (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8581 no_local_addr = TRUE;
8582 }
8583
8584 if (remote_addr.sa.sa_len == 0 ||
8585 (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8586 (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8587 no_remote_addr = TRUE;
8588 remote_family = remote_addr.sa.sa_family;
8589 }
8590
8591 returned_result->routed_interface_index = 0;
8592 struct rtentry *rt = NULL;
8593 if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8594 // Treat the output bound interface as the routed interface for local address
8595 // validation later.
8596 returned_result->routed_interface_index = output_bound_interface;
8597 } else {
8598 if (no_remote_addr) {
8599 memset(&remote_addr, 0, sizeof(remote_addr));
8600 if (remote_family == AF_INET6) {
8601 // Reset address to ::
8602 remote_addr.sa.sa_family = AF_INET6;
8603 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8604 } else {
8605 // Reset address to 0.0.0.0
8606 remote_addr.sa.sa_family = AF_INET;
8607 remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8608 }
8609 }
8610
8611 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8612 output_bound_interface);
8613
8614 if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8615 IS_INTF_CLAT46(rt->rt_ifp)) {
8616 rtfree(rt);
8617 rt = NULL;
8618 returned_result->routed_interface_index = 0;
8619 }
8620
8621 if (no_remote_addr && remote_family == AF_UNSPEC &&
8622 (rt == NULL || rt->rt_ifp == NULL)) {
8623 // Route lookup for default IPv4 failed, try IPv6
8624
8625 // Cleanup old route if necessary
8626 if (rt != NULL) {
8627 rtfree(rt);
8628 rt = NULL;
8629 }
8630
8631 // Reset address to ::
8632 memset(&remote_addr, 0, sizeof(remote_addr));
8633 remote_addr.sa.sa_family = AF_INET6;
8634 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8635
8636 // Get route
8637 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8638 output_bound_interface);
8639 }
8640
8641 if (rt != NULL &&
8642 rt->rt_ifp != NULL) {
8643 returned_result->routed_interface_index = rt->rt_ifp->if_index;
8644 /*
8645 * For local addresses, we allow the interface scope to be
8646 * either the loopback interface or the interface hosting the
8647 * local address.
8648 */
8649 if (bound_interface_index != IFSCOPE_NONE &&
8650 rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8651 (output_bound_interface == lo_ifp->if_index ||
8652 rt->rt_ifp->if_index == lo_ifp->if_index ||
8653 rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8654 struct sockaddr_storage dst;
8655 unsigned int ifscope = bound_interface_index;
8656
8657 /*
8658 * Transform dst into the internal routing table form
8659 */
8660 (void) sa_copy(SA(&remote_addr),
8661 &dst, &ifscope);
8662
8663 if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8664 rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8665 returned_result->routed_interface_index =
8666 bound_interface_index;
8667 }
8668 }
8669 }
8670 }
8671
8672 if (returned_result->routed_interface_index != 0 &&
8673 returned_result->routed_interface_index != lo_ifp->if_index && // Loopback can accept any local address
8674 !no_local_addr) {
8675 // Transform local_addr into the ifaddr form
8676 // IPv6 Scope IDs are always embedded in the ifaddr list
8677 struct sockaddr_storage local_address_sanitized;
8678 u_int ifscope = IFSCOPE_NONE;
8679 (void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8680 SIN(&local_address_sanitized)->sin_port = 0;
8681 if (local_address_sanitized.ss_family == AF_INET6) {
8682 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8683 SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8684 }
8685 }
8686
8687 // Validate local address on routed interface
8688 struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8689 if (ifa == NULL) {
8690 // Interface address not found, reject route
8691 returned_result->routed_interface_index = 0;
8692 if (rt != NULL) {
8693 rtfree(rt);
8694 rt = NULL;
8695 }
8696 } else {
8697 ifaddr_release(ifa);
8698 ifa = NULL;
8699 }
8700 }
8701
8702 if (flags != NULL) {
8703 #if SKYWALK
8704 if (kernel_is_macos_or_server()) {
8705 enum net_filter_event_subsystems filters = net_filter_event_get_state();
8706
8707 if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8708 *flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8709 }
8710 if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8711 *flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8712 }
8713 if (filters & NET_FILTER_EVENT_ALF) {
8714 *flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8715 }
8716 if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8717 *flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8718 }
8719 }
8720 #endif /* SKYWALK */
8721 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8722 // Check for local/direct
8723 bool is_local = FALSE;
8724 if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8725 is_local = TRUE;
8726 } else if (returned_result->routed_interface_index != 0 &&
8727 !no_remote_addr) {
8728 // Clean up the address before comparison with interface addresses
8729
8730 // Transform remote_addr into the ifaddr form
8731 // IPv6 Scope IDs are always embedded in the ifaddr list
8732 struct sockaddr_storage remote_address_sanitized;
8733 u_int ifscope = IFSCOPE_NONE;
8734 (void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8735 SIN(&remote_address_sanitized)->sin_port = 0;
8736 if (remote_address_sanitized.ss_family == AF_INET6) {
8737 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8738 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8739 }
8740 }
8741
8742 // Check if remote address is an interface address
8743 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8744 if (ifa != NULL && ifa->ifa_ifp != NULL) {
8745 u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8746 if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8747 if_index_for_remote_addr == lo_ifp->if_index) {
8748 is_local = TRUE;
8749 }
8750 }
8751 if (ifa != NULL) {
8752 ifaddr_release(ifa);
8753 ifa = NULL;
8754 }
8755 }
8756
8757 if (is_local) {
8758 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8759 } else if (rt != NULL) {
8760 if (rt->rt_flags & RTF_GLOBAL) {
8761 *flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8762 } else if (!(rt->rt_flags & RTF_GATEWAY) &&
8763 (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8764 // Route is directly accessible
8765 *flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8766 }
8767 }
8768
8769 if (rt != NULL &&
8770 rt->rt_ifp != NULL) {
8771 // Check probe status
8772 if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8773 *flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8774 }
8775
8776 if (if_link_heuristics_enabled(rt->rt_ifp)) {
8777 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_HEURISTICS;
8778 }
8779
8780 if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8781 struct if_cellular_status_v1 *ifsr;
8782
8783 ifnet_lock_shared(rt->rt_ifp);
8784 lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8785
8786 if (rt->rt_ifp->if_link_status != NULL) {
8787 ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8788
8789 if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8790 if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8791 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8792 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8793 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8794 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8795 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8796 }
8797 }
8798 }
8799 lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8800 ifnet_lock_done(rt->rt_ifp);
8801 }
8802
8803 // Check link quality
8804 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8805 (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8806 rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8807 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8808 }
8809
8810 // Check QoS marking (fastlane)
8811 for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8812 if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8813 *flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8814 // If the route can use QoS markings, stop iterating route rules
8815 break;
8816 }
8817 }
8818
8819 if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8820 *flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8821 }
8822
8823 if (traffic_class == SO_TC_BK_SYS) {
8824 // Block BK_SYS traffic if interface is throttled
8825 u_int32_t throttle_level = 0;
8826 if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8827 if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8828 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8829 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8830 }
8831 }
8832 }
8833 }
8834 }
8835
8836 u_int interface_to_check = returned_result->routed_interface_index;
8837 if (interface_to_check == 0) {
8838 interface_to_check = output_bound_interface;
8839 }
8840 union necp_sockaddr_union default_address;
8841 struct rtentry *v4Route = NULL;
8842 struct rtentry *v6Route = NULL;
8843
8844 memset(&default_address, 0, sizeof(default_address));
8845
8846 // Reset address to 0.0.0.0
8847 default_address.sa.sa_family = AF_INET;
8848 default_address.sa.sa_len = sizeof(struct sockaddr_in);
8849 v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8850 returned_result->routed_interface_index);
8851
8852 // Reset address to ::
8853 default_address.sa.sa_family = AF_INET6;
8854 default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8855 v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8856 returned_result->routed_interface_index);
8857
8858 if (v4Route != NULL) {
8859 if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8860 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8861 }
8862 if (returned_v4_gateway != NULL &&
8863 v4Route->rt_gateway != NULL &&
8864 v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8865 memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8866 memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8867 }
8868 rtfree(v4Route);
8869 v4Route = NULL;
8870 }
8871
8872 if (v6Route != NULL) {
8873 if (v6Route->rt_ifp != NULL) {
8874 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8875
8876 if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8877 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8878 }
8879 }
8880 if (returned_v6_gateway != NULL &&
8881 v6Route->rt_gateway != NULL &&
8882 v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8883 SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8884 }
8885 rtfree(v6Route);
8886 v6Route = NULL;
8887 }
8888 }
8889
8890 // Take two passes through the rule list: first for rules that don't match based on agents,
8891 // second for rules that match based on agents. Since rules can modify the agent list itself,
8892 // this makes the logic more deterministic. This allows a non-agent matching rule to remove
8893 // an agent before it is used for matching later.
8894 size_t route_rule_index = 0;
8895 bool second_pass = false;
8896 while (route_rule_index < route_rule_id_array_count) {
8897 bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8898 if (rule_matches_agents != second_pass) {
8899 // Process rules that match based on agents only in the second pass
8900 route_rule_index++;
8901 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8902 route_rule_index = 0;
8903 second_pass = true;
8904 }
8905 continue;
8906 }
8907
8908 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8909 bool ultra_constrained_denied = false;
8910 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, &ultra_constrained_denied);
8911 if (!route_is_allowed) {
8912 // If the route is blocked, treat the lookup as a drop
8913 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8914 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8915
8916 if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8917 if (reason != NULL) {
8918 if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8919 *reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8920 } else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8921 *reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8922 }
8923 }
8924 necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8925 } else if (ultra_constrained_denied) {
8926 if (reason != NULL) {
8927 *reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8928 }
8929 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_ULTRA_CONSTRAINED);
8930 }
8931
8932 // If the route gets denied, stop matching rules
8933 break;
8934 }
8935
8936 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8937 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8938 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8939 route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8940 if (flow_divert_control_unit != 0) {
8941 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8942 returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8943 }
8944 if (flow_divert_aggregate_unit != 0) {
8945 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8946 }
8947 }
8948
8949 // Check if there is a route rule that adds or removes an agent
8950 bool remove = false;
8951 u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8952 if (netagent_id != 0) {
8953 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
8954 if (mapping != NULL) {
8955 bool agent_already_present = false;
8956 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8957 if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8958 // Found the agent already present
8959 agent_already_present = true;
8960 if (remove) {
8961 // Mark as remove if necessary
8962 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8963 }
8964 } else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8965 // Found open slot
8966 if (!agent_already_present) {
8967 uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8968 if (remove) {
8969 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8970 } else {
8971 returned_result->netagent_use_flags[netagent_cursor] = 0;
8972 }
8973 }
8974 break;
8975 }
8976 }
8977 }
8978
8979 // Update the local netagent_ids array for future evaluations
8980 if (remove) {
8981 // Check if the agent ID is in the array, and remove it
8982 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8983 if (netagent_id == netagent_ids[netagent_cursor]) {
8984 netagent_ids[netagent_cursor] = 0;
8985 }
8986 }
8987 } else {
8988 // Check if the agent ID is not yet in the array, and add it
8989 bool found = false;
8990 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8991 if (netagent_id == netagent_ids[netagent_cursor]) {
8992 found = true;
8993 break;
8994 }
8995 }
8996 if (!found) {
8997 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8998 if (netagent_ids[netagent_cursor] == 0) {
8999 // Empty slot, add the agent
9000 netagent_ids[netagent_cursor] = netagent_id;
9001 break;
9002 }
9003 }
9004 }
9005 }
9006 }
9007
9008 route_rule_index++;
9009 if (route_rule_index == route_rule_id_array_count && !second_pass) {
9010 route_rule_index = 0;
9011 second_pass = true;
9012 }
9013 }
9014
9015 if (rt != NULL && rt->rt_ifp != NULL) {
9016 const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
9017 const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
9018 const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
9019 IFNET_IS_EXPENSIVE(rt->rt_ifp));
9020 const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
9021 IFNET_IS_CONSTRAINED(rt->rt_ifp));
9022 const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
9023 IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
9024 (!if_ultra_constrained_default_allowed && !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT))));
9025
9026 const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
9027 if (!is_listener && !is_browser) {
9028 if (reason != NULL) {
9029 if (expensive_prohibited) {
9030 *reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
9031 } else if (constrained_prohibited) {
9032 *reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
9033 } else if (ultra_constrained_not_allowed) {
9034 *reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
9035 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_ULTRA_CONSTRAINED);
9036 }
9037 }
9038 if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
9039 // If a property of the interface was not allowed, treat it as a drop
9040 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
9041 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
9042 }
9043 }
9044
9045 if ((extended_client_flags & NECP_CLIENT_PARAMETER_EXTENDED_FLAG_AOP2_OFFLOAD) &&
9046 ((rt->rt_ifp->if_xflags & IFXF_RX_FLOW_STEERING) == 0)) {
9047 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
9048 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
9049 }
9050 }
9051
9052 if (rt != NULL) {
9053 if (returned_route != NULL) {
9054 *returned_route = rt;
9055 } else {
9056 rtfree(rt);
9057 }
9058 rt = NULL;
9059 }
9060
9061 done:
9062 // Unlock
9063 lck_rw_done(&necp_kernel_policy_lock);
9064
9065 if (release_eproc && effective_proc != PROC_NULL) {
9066 proc_rele(effective_proc);
9067 }
9068 #if defined(XNU_TARGET_OS_OSX)
9069 if (responsible_proc != PROC_NULL) {
9070 proc_rele(responsible_proc);
9071 }
9072 #endif
9073
9074 if (cred != NULL) {
9075 kauth_cred_unref(&cred);
9076 }
9077
9078 return error;
9079 }
9080
9081 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)9082 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
9083 {
9084 struct rtentry *rt = NULL;
9085 bool is_local = FALSE;
9086
9087 if (remote_addr == NULL) {
9088 return NULL;
9089 }
9090
9091 if (remote_addr->sa.sa_len == 0 ||
9092 (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
9093 (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
9094 return FALSE;
9095 }
9096
9097 // Lookup route regardless of the scoped interface to check if
9098 // remote address is in a local network.
9099 rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
9100
9101 if (rt == NULL) {
9102 goto done;
9103 }
9104 if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
9105 goto free_rt;
9106 }
9107 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
9108
9109 free_rt:
9110 rtfree(rt);
9111
9112 done:
9113 return is_local;
9114 }
9115
9116 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)9117 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
9118 necp_app_id app_id,
9119 necp_app_id real_app_id,
9120 uint8_t is_entitled,
9121 u_int32_t account_id,
9122 struct substring domain,
9123 u_int8_t domain_dot_count,
9124 const char *url __null_terminated,
9125 pid_t pid,
9126 int32_t pid_version,
9127 uid_t uid,
9128 uid_t real_uid,
9129 u_int32_t bound_interface_index,
9130 u_int32_t traffic_class,
9131 u_int16_t protocol,
9132 union necp_sockaddr_union *local,
9133 union necp_sockaddr_union *remote,
9134 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9135 u_int32_t num_required_agent_types,
9136 bool has_client,
9137 uint32_t client_flags,
9138 int is_platform_binary,
9139 bool has_signed_result,
9140 proc_t proc,
9141 u_int16_t pf_tag,
9142 u_int16_t scheme_port,
9143 struct rtentry *rt,
9144 bool is_loopback,
9145 int debug,
9146 bool real_is_platform_binary,
9147 u_int32_t bound_interface_flags,
9148 u_int32_t bound_interface_eflags,
9149 u_int32_t bound_interface_xflags,
9150 struct necp_socket_info *info,
9151 bool is_delegated,
9152 struct socket *socket)
9153 {
9154 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9155 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9156 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9157 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9158 "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
9159 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9160 if (bound_interface_index == cond_bound_interface_index) {
9161 // No match, matches forbidden interface
9162 return FALSE;
9163 }
9164 } else {
9165 if (bound_interface_index != cond_bound_interface_index) {
9166 // No match, does not match required interface
9167 return FALSE;
9168 }
9169 }
9170 }
9171 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9172 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9173 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9174 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9175 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9176 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9177 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9178 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9179 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9180 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9181 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9182 // No match, matches some forbidden interface flags
9183 return FALSE;
9184 }
9185 } else {
9186 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9187 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9188 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9189 // No match, does not match some required interface xflags
9190 return FALSE;
9191 }
9192 }
9193 }
9194 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9195 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9196 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
9197 if (bound_interface_index != 0) {
9198 // No match, requires a non-bound packet
9199 return FALSE;
9200 }
9201 }
9202 }
9203
9204 if (kernel_policy->condition_mask == 0) {
9205 return TRUE;
9206 }
9207
9208 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9209 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
9210 "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
9211 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
9212 if (app_id == kernel_policy->cond_app_id) {
9213 // No match, matches forbidden application
9214 return FALSE;
9215 }
9216 } else {
9217 if (app_id != kernel_policy->cond_app_id) {
9218 // No match, does not match required application
9219 return FALSE;
9220 }
9221 }
9222
9223 // Check signing identifier only after APP ID matched
9224 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
9225 kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9226 u_int8_t matched = necp_boolean_state_false;
9227 const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
9228 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
9229 "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
9230 kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
9231 signing_id ? signing_id : "<n/a>");
9232 if (signing_id != NULL) {
9233 if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
9234 matched = necp_boolean_state_true;
9235 }
9236 }
9237
9238 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9239 if (matched == necp_boolean_state_true) {
9240 return FALSE;
9241 }
9242 } else {
9243 if (matched != necp_boolean_state_true) {
9244 return FALSE;
9245 }
9246 }
9247 }
9248 }
9249
9250 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9251 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
9252 "NECP_KERNEL_CONDITION_REAL_APP_ID",
9253 kernel_policy->cond_real_app_id, real_app_id);
9254 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9255 if (real_app_id == kernel_policy->cond_real_app_id) {
9256 // No match, matches forbidden application
9257 return FALSE;
9258 }
9259 } else {
9260 if (real_app_id != kernel_policy->cond_real_app_id) {
9261 // No match, does not match required application
9262 return FALSE;
9263 }
9264 }
9265 }
9266
9267 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9268 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
9269 if (!has_client) {
9270 return FALSE;
9271 }
9272 }
9273
9274 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9275 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
9276 if (!is_entitled) {
9277 // Process is missing entitlement
9278 return FALSE;
9279 }
9280 }
9281
9282 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9283 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);
9284 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9285 if (is_platform_binary) {
9286 // Process is platform binary
9287 return FALSE;
9288 }
9289 } else {
9290 if (!is_platform_binary) {
9291 // Process is not platform binary
9292 return FALSE;
9293 }
9294 }
9295 }
9296
9297 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9298 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
9299 if (has_signed_result == 0) {
9300 // Client did not have a system-signed result
9301 return FALSE;
9302 }
9303 }
9304
9305 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
9306 if (proc != NULL) {
9307 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
9308 kernel_policy->cond_sdk_version.platform,
9309 kernel_policy->cond_sdk_version.min_version,
9310 kernel_policy->cond_sdk_version.version,
9311 proc_platform(proc),
9312 proc_min_sdk(proc),
9313 proc_sdk(proc));
9314 if (kernel_policy->cond_sdk_version.platform != 0) {
9315 if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
9316 // Process does not match platform
9317 return FALSE;
9318 }
9319 }
9320
9321 if (kernel_policy->cond_sdk_version.min_version != 0) {
9322 if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
9323 // Process min version is older than required min version
9324 return FALSE;
9325 }
9326 }
9327
9328 if (kernel_policy->cond_sdk_version.version != 0) {
9329 if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
9330 // Process SDK version is older than required version
9331 return FALSE;
9332 }
9333 }
9334 }
9335 }
9336
9337 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
9338 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
9339 if (kernel_policy->cond_custom_entitlement != NULL) {
9340 if (proc == NULL) {
9341 // No process found, cannot check entitlement
9342 return FALSE;
9343 }
9344 task_t __single task = proc_task(proc);
9345 if (task == NULL ||
9346 !IOTaskHasEntitlementAsBooleanOrObject(task, kernel_policy->cond_custom_entitlement)) {
9347 // Process is missing custom entitlement
9348 return FALSE;
9349 }
9350 }
9351 }
9352
9353 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9354 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
9355 "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
9356 // Exact match requires the number of dots to match (no suffix matching allowed)
9357 bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
9358 necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
9359 if (domain_matches && socket != NULL) {
9360 socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9361 }
9362 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9363 if (domain_matches) {
9364 // No match, matches forbidden domain
9365 return FALSE;
9366 }
9367 } else {
9368 if (!domain_matches) {
9369 // No match, does not match required domain
9370 return FALSE;
9371 }
9372 }
9373 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9374 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
9375 "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
9376 bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
9377 if (domain_matches && socket != NULL) {
9378 socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9379 }
9380 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9381 if (domain_matches) {
9382 // No match, matches forbidden domain
9383 return FALSE;
9384 }
9385 } else {
9386 if (!domain_matches) {
9387 // No match, does not match required domain
9388 return FALSE;
9389 }
9390 }
9391 }
9392
9393 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9394 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9395 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (ID)", kernel_policy->cond_domain_filter, 0);
9396 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9397 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (domain)", "<n/a>", domain.string);
9398 bool domain_matches = false;
9399 if (NECP_IS_DOMAIN_FILTER_ID(kernel_policy->cond_domain_filter)) {
9400 struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
9401 if (filter != NULL && filter->filter != NULL) {
9402 domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
9403 }
9404 } else {
9405 domain_matches = necp_match_domain_with_trie(&necp_global_domain_trie_list, kernel_policy->cond_domain_filter, domain.string, domain.length);
9406 if (debug) {
9407 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);
9408 }
9409 }
9410 if (domain_matches && socket != NULL) {
9411 socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9412 }
9413 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9414 if (domain_matches) {
9415 // No match, matches forbidden domain
9416 return FALSE;
9417 }
9418 } else {
9419 if (!domain_matches) {
9420 // No match, does not match required domain
9421 return FALSE;
9422 }
9423 }
9424 }
9425
9426 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
9427 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
9428 "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
9429 bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
9430 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
9431 if (url_matches) {
9432 // No match, matches forbidden url
9433 return FALSE;
9434 }
9435 } else {
9436 if (!url_matches) {
9437 // No match, does not match required url
9438 return FALSE;
9439 }
9440 }
9441 }
9442
9443 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9444 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
9445 "NECP_KERNEL_CONDITION_ACCOUNT_ID",
9446 kernel_policy->cond_account_id, account_id);
9447 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9448 if (account_id == kernel_policy->cond_account_id) {
9449 // No match, matches forbidden account
9450 return FALSE;
9451 }
9452 } else {
9453 if (account_id != kernel_policy->cond_account_id) {
9454 // No match, does not match required account
9455 return FALSE;
9456 }
9457 }
9458 }
9459
9460 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
9461 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
9462 "NECP_KERNEL_CONDITION_PID",
9463 kernel_policy->cond_pid, pid);
9464 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
9465 if (pid == kernel_policy->cond_pid) {
9466 // No match, matches forbidden pid
9467 return FALSE;
9468 }
9469 if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
9470 return FALSE;
9471 }
9472 } else {
9473 if (pid != kernel_policy->cond_pid) {
9474 // No match, does not match required pid
9475 return FALSE;
9476 }
9477 if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
9478 return FALSE;
9479 }
9480 }
9481 }
9482
9483 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9484 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9485 "NECP_KERNEL_CONDITION_UID",
9486 kernel_policy->cond_uid, uid);
9487 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9488 if (uid == kernel_policy->cond_uid) {
9489 // No match, matches forbidden uid
9490 return FALSE;
9491 }
9492 } else {
9493 if (uid != kernel_policy->cond_uid) {
9494 // No match, does not match required uid
9495 return FALSE;
9496 }
9497 }
9498 }
9499
9500 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9501 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9502 "NECP_KERNEL_CONDITION_REAL_UID",
9503 kernel_policy->cond_real_uid, real_uid);
9504 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9505 if (real_uid == kernel_policy->cond_real_uid) {
9506 // No match, matches forbidden uid
9507 return FALSE;
9508 }
9509 } else {
9510 if (real_uid != kernel_policy->cond_real_uid) {
9511 // No match, does not match required uid
9512 return FALSE;
9513 }
9514 }
9515 }
9516
9517 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9518 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9519 kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9520 traffic_class, 0, 0);
9521 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9522 if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9523 traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9524 // No match, matches forbidden traffic class
9525 return FALSE;
9526 }
9527 } else {
9528 if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9529 traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9530 // No match, does not match required traffic class
9531 return FALSE;
9532 }
9533 }
9534 }
9535
9536 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9537 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9538 "NECP_KERNEL_CONDITION_PROTOCOL",
9539 kernel_policy->cond_protocol, protocol);
9540 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9541 if (protocol == kernel_policy->cond_protocol) {
9542 // No match, matches forbidden protocol
9543 return FALSE;
9544 }
9545 } else {
9546 if (protocol != kernel_policy->cond_protocol) {
9547 // No match, does not match required protocol
9548 return FALSE;
9549 }
9550 }
9551 }
9552
9553 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9554 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9555 kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9556 "n/a", "n/a", "n/a");
9557 bool matches_agent_type = FALSE;
9558 for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9559 struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9560 if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9561 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) &&
9562 (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9563 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)) {
9564 // Found a required agent that matches
9565 matches_agent_type = TRUE;
9566 break;
9567 }
9568 }
9569 if (!matches_agent_type) {
9570 return FALSE;
9571 }
9572 }
9573
9574 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9575 bool is_local = FALSE;
9576 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9577
9578 if (rt != NULL) {
9579 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9580 } else {
9581 is_local = necp_is_route_local(remote, include_local_addresses);
9582 }
9583 if (info != NULL) {
9584 info->is_local = is_local;
9585 }
9586
9587 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);
9588 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9589 if (is_local) {
9590 // Match local-networks, fail
9591 return FALSE;
9592 }
9593 } else {
9594 if (!is_local) {
9595 // Either no route to validate or no match for local networks
9596 return FALSE;
9597 }
9598 }
9599 }
9600
9601 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9602 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9603 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9604 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9605 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9606 if (inRange) {
9607 return FALSE;
9608 }
9609 } else {
9610 if (!inRange) {
9611 return FALSE;
9612 }
9613 }
9614 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9615 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9616 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);
9617 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9618 if (inSubnet) {
9619 return FALSE;
9620 }
9621 } else {
9622 if (!inSubnet) {
9623 return FALSE;
9624 }
9625 }
9626 }
9627 }
9628
9629 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9630 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9631 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9632 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9633 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9634 if (inRange) {
9635 return FALSE;
9636 }
9637 } else {
9638 if (!inRange) {
9639 return FALSE;
9640 }
9641 }
9642 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9643 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9644 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);
9645 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9646 if (inSubnet) {
9647 return FALSE;
9648 }
9649 } else {
9650 if (!inSubnet) {
9651 return FALSE;
9652 }
9653 }
9654 }
9655 }
9656
9657 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9658 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9659 "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9660 kernel_policy->cond_client_flags, client_flags);
9661 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9662 if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9663 // Flags do match, and condition is negative, fail.
9664 return FALSE;
9665 }
9666 } else {
9667 if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9668 // Flags do not match, fail.
9669 return FALSE;
9670 }
9671 }
9672 }
9673
9674 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9675 bool isEmpty = necp_addr_is_empty(SA(local));
9676 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9677 "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9678 0, isEmpty);
9679 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9680 if (isEmpty) {
9681 return FALSE;
9682 }
9683 } else {
9684 if (!isEmpty) {
9685 return FALSE;
9686 }
9687 }
9688 }
9689
9690 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9691 bool isEmpty = necp_addr_is_empty(SA(remote));
9692 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9693 "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9694 0, isEmpty);
9695 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9696 if (isEmpty) {
9697 return FALSE;
9698 }
9699 } else {
9700 if (!isEmpty) {
9701 return FALSE;
9702 }
9703 }
9704 }
9705
9706 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9707 u_int16_t remote_port = 0;
9708 if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9709 remote_port = SIN(remote)->sin_port;
9710 }
9711 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9712 "NECP_KERNEL_CONDITION_SCHEME_PORT",
9713 scheme_port, remote_port);
9714 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9715 if (kernel_policy->cond_scheme_port == scheme_port ||
9716 kernel_policy->cond_scheme_port == remote_port) {
9717 return FALSE;
9718 }
9719 } else {
9720 if (kernel_policy->cond_scheme_port != scheme_port &&
9721 kernel_policy->cond_scheme_port != remote_port) {
9722 return FALSE;
9723 }
9724 }
9725 }
9726
9727 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9728 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9729 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9730 kernel_policy->cond_packet_filter_tags,
9731 pf_tag);
9732 bool tags_matched = false;
9733 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9734 if (pf_tag == PF_TAG_ID_STACK_DROP) {
9735 tags_matched = true;
9736 }
9737 }
9738
9739 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9740 if (tags_matched) {
9741 return FALSE;
9742 }
9743 } else {
9744 if (!tags_matched) {
9745 return FALSE;
9746 }
9747 }
9748 }
9749
9750 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9751 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9752 "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9753 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9754 if (is_loopback) {
9755 return FALSE;
9756 }
9757 } else {
9758 if (!is_loopback) {
9759 return FALSE;
9760 }
9761 }
9762 }
9763
9764 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9765 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9766 "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9767 if (is_delegated) {
9768 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9769 if (real_is_platform_binary) {
9770 return FALSE;
9771 }
9772 } else {
9773 if (!real_is_platform_binary) {
9774 return FALSE;
9775 }
9776 }
9777 } else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9778 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9779 // If the connection is not delegated, and the policy did not specify a particular effective process UUID
9780 // or PID, check the process directly
9781 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9782 if (is_platform_binary) {
9783 return FALSE;
9784 }
9785 } else {
9786 if (!is_platform_binary) {
9787 return FALSE;
9788 }
9789 }
9790 }
9791 }
9792
9793 return TRUE;
9794 }
9795
9796 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9797 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9798 {
9799 return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9800 }
9801
9802 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)9803 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)
9804 {
9805 struct socket *so = NULL;
9806 proc_t sock_proc = NULL;
9807 proc_t curr_proc = current_proc();
9808
9809 memset(info, 0, sizeof(struct necp_socket_info));
9810
9811 so = inp->inp_socket;
9812
9813 info->drop_order = drop_order;
9814 info->is_loopback = is_loopback;
9815 info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9816
9817 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9818 necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9819 info->uid = kauth_cred_getuid(so->so_cred);
9820 info->real_uid = info->uid;
9821 }
9822
9823 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9824 info->traffic_class = so->so_traffic_class;
9825 }
9826
9827 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9828 info->has_client = !uuid_is_null(inp->necp_client_uuid);
9829 }
9830
9831 if (inp->inp_ip_p) {
9832 info->protocol = inp->inp_ip_p;
9833 } else {
9834 info->protocol = SOCK_PROTO(so);
9835 }
9836
9837 if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9838 u_int32_t responsible_application_id = 0;
9839
9840 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9841 if (existing_mapping) {
9842 info->application_id = existing_mapping->id;
9843 }
9844
9845 #if defined(XNU_TARGET_OS_OSX)
9846 if (so->so_rpid > 0) {
9847 existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9848 if (existing_mapping != NULL) {
9849 responsible_application_id = existing_mapping->id;
9850 }
9851 }
9852 #endif
9853
9854 if (responsible_application_id > 0) {
9855 info->real_application_id = info->application_id;
9856 info->application_id = responsible_application_id;
9857 info->used_responsible_pid = true;
9858 } else if (!(so->so_flags & SOF_DELEGATED)) {
9859 info->real_application_id = info->application_id;
9860 } else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9861 struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9862 if (real_existing_mapping) {
9863 info->real_application_id = real_existing_mapping->id;
9864 }
9865 }
9866 }
9867
9868 pid_t socket_pid =
9869 #if defined(XNU_TARGET_OS_OSX)
9870 info->used_responsible_pid ? so->so_rpid :
9871 #endif
9872 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9873 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9874 sock_proc = proc_find(socket_pid);
9875 if (socket_proc) {
9876 *socket_proc = sock_proc;
9877 }
9878 }
9879
9880 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9881 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9882 info->is_entitled = necp_task_has_match_entitlement(task);
9883 if (!info->is_entitled) {
9884 // Task does not have entitlement, check the parent task
9885 necp_get_parent_is_entitled(task, info);
9886 }
9887 }
9888
9889 info->pid = socket_pid;
9890 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9891 info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9892 }
9893
9894 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9895 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9896 if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9897 info->is_platform_binary = true;
9898 } else if (so->so_rpid != 0) {
9899 proc_t responsible_proc = proc_find(so->so_rpid);
9900 if (responsible_proc != NULL) {
9901 if (necp_is_platform_binary(responsible_proc)) {
9902 info->is_platform_binary = true;
9903 info->used_responsible_pid = true;
9904 }
9905 proc_rele(responsible_proc);
9906 }
9907 }
9908 }
9909
9910 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9911 proc_t real_proc = curr_proc;
9912 bool release_real_proc = false;
9913 if (so->last_pid != proc_pid(real_proc)) {
9914 if (so->last_pid == socket_pid && sock_proc != NULL) {
9915 real_proc = sock_proc;
9916 } else {
9917 proc_t last_proc = proc_find(so->last_pid);
9918 if (last_proc != NULL) {
9919 real_proc = last_proc;
9920 release_real_proc = true;
9921 }
9922 }
9923 }
9924 if (real_proc != NULL) {
9925 if (real_proc == kernproc) {
9926 info->real_is_platform_binary = true;
9927 } else {
9928 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9929 }
9930 if (release_real_proc) {
9931 proc_rele(real_proc);
9932 }
9933 }
9934 }
9935
9936 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9937 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9938 if (existing_mapping) {
9939 info->account_id = existing_mapping->id;
9940 }
9941 }
9942
9943 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9944 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9945 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9946 info->domain = inp->inp_necp_attributes.inp_domain;
9947 }
9948
9949 if (override_bound_interface) {
9950 info->bound_interface_index = override_bound_interface;
9951 } else {
9952 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9953 info->bound_interface_index = inp->inp_boundifp->if_index;
9954 }
9955 }
9956
9957 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9958 info->bound_interface_index != IFSCOPE_NONE) {
9959 ifnet_head_lock_shared();
9960 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9961 if (interface != NULL) {
9962 info->bound_interface_flags = interface->if_flags;
9963 info->bound_interface_eflags = interface->if_eflags;
9964 info->bound_interface_xflags = interface->if_xflags;
9965 }
9966 ifnet_head_done();
9967 }
9968
9969 bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9970 uuid_is_null(inp->necp_client_uuid) &&
9971 necp_socket_has_resolver_signature(inp));
9972 if ((necp_data_tracing_level && necp_data_tracing_port) ||
9973 necp_restrict_multicast ||
9974 needs_address_for_signature ||
9975 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) ||
9976 NEED_DGRAM_FLOW_TRACKING(so)) {
9977 if (override_local_addr != NULL) {
9978 if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9979 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9980 if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9981 struct sockaddr_in sin;
9982 in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9983 memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9984 memcpy(&info->local_addr, &sin, sin.sin_len);
9985 }
9986 } else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9987 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9988 }
9989 } else {
9990 if (inp->inp_vflag & INP_IPV6) {
9991 SIN6(&info->local_addr)->sin6_family = AF_INET6;
9992 SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9993 SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9994 memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9995 } else if (inp->inp_vflag & INP_IPV4) {
9996 SIN(&info->local_addr)->sin_family = AF_INET;
9997 SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9998 SIN(&info->local_addr)->sin_port = inp->inp_lport;
9999 memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
10000 }
10001 }
10002
10003 if (override_remote_addr != NULL) {
10004 if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
10005 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
10006 if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
10007 struct sockaddr_in sin;
10008 in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
10009 memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
10010 memcpy(&info->remote_addr, &sin, sin.sin_len);
10011 }
10012 } else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
10013 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
10014 }
10015 } else {
10016 if (inp->inp_vflag & INP_IPV6) {
10017 SIN6(&info->remote_addr)->sin6_family = AF_INET6;
10018 SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
10019 SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
10020 memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
10021 } else if (inp->inp_vflag & INP_IPV4) {
10022 SIN(&info->remote_addr)->sin_family = AF_INET;
10023 SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
10024 SIN(&info->remote_addr)->sin_port = inp->inp_fport;
10025 memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
10026 }
10027 }
10028 // Clear the embedded scope id from v6 addresses
10029 if (info->local_addr.sa.sa_family == AF_INET6) {
10030 struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
10031 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
10032 if (sin6->sin6_addr.s6_addr16[1] != 0) {
10033 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
10034 sin6->sin6_addr.s6_addr16[1] = 0;
10035 }
10036 }
10037 }
10038 if (info->remote_addr.sa.sa_family == AF_INET6) {
10039 struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
10040 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
10041 if (sin6->sin6_addr.s6_addr16[1] != 0) {
10042 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
10043 sin6->sin6_addr.s6_addr16[1] = 0;
10044 }
10045 }
10046 }
10047 }
10048
10049 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
10050 // For checking sockets, only validate that there is an NECP client present. It will have
10051 // already checked for the signature.
10052 if (!uuid_is_null(inp->necp_client_uuid)) {
10053 info->has_system_signed_result = true;
10054 } else {
10055 info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
10056 }
10057 }
10058
10059 if (NEED_DGRAM_FLOW_TRACKING(so)) {
10060 info->soflow_entry = soflow_get_flow(so, NULL, &(info->remote_addr.sa), NULL, 0, override_direction, input_ifindex);
10061 } else {
10062 info->soflow_entry = NULL;
10063 }
10064
10065 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
10066 info->client_flags = 0;
10067 if (INP_NO_CONSTRAINED(inp)) {
10068 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
10069 }
10070 if (INP_NO_EXPENSIVE(inp)) {
10071 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
10072 }
10073 if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
10074 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
10075 }
10076 if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
10077 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
10078 }
10079 if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
10080 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
10081 }
10082 if (NEED_DGRAM_FLOW_TRACKING(so)) {
10083 // If the socket has a flow entry for this 4-tuple then check if the flow is outgoing
10084 // and set the inbound flag accordingly. Otherwise use the direction to set the inbound flag.
10085 if (info->soflow_entry != NULL) {
10086 if (!info->soflow_entry->soflow_outgoing) {
10087 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
10088 }
10089 } else if (override_direction == SOFLOW_DIRECTION_INBOUND) {
10090 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
10091 }
10092 } else {
10093 // If the socket is explicitly marked as inbound then set the inbound flag.
10094 if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
10095 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
10096 }
10097 }
10098 if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
10099 inp->inp_flags2 & INP2_EXTERNAL_PORT) {
10100 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
10101 }
10102 if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
10103 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
10104 }
10105 if (inp->inp_socket->so_options & SO_REUSEPORT) {
10106 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
10107 }
10108 }
10109 }
10110
10111 #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)
10112
10113 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,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)10114 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
10115 struct necp_socket_info *info,
10116 necp_kernel_policy_filter *return_filter,
10117 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
10118 size_t *return_route_rule_id_array_count,
10119 size_t route_rule_id_array_count,
10120 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
10121 size_t netagent_array_count,
10122 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
10123 size_t netagent_use_flags_array_count,
10124 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
10125 u_int32_t num_required_agent_types,
10126 proc_t proc,
10127 u_int16_t pf_tag,
10128 necp_kernel_policy_id *skip_policy_id,
10129 struct rtentry *rt,
10130 necp_kernel_policy_result *return_drop_dest_policy_result,
10131 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
10132 u_int32_t *return_flow_divert_aggregate_unit,
10133 struct socket *so,
10134 int debug)
10135 {
10136 struct necp_kernel_socket_policy *matched_policy = NULL;
10137 u_int32_t skip_order = 0;
10138 u_int32_t skip_session_order = 0;
10139 bool skipped_ip_result = false;
10140 size_t route_rule_id_count = 0;
10141 int i;
10142 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10143 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
10144 memset(&netagent_ids, 0, sizeof(netagent_ids));
10145 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
10146 size_t netagent_cursor = 0;
10147 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10148 size_t netagent_array_count_adjusted = netagent_array_count;
10149 if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
10150 netagent_array_count_adjusted = netagent_use_flags_array_count;
10151 }
10152
10153 if (return_drop_all_bypass != NULL) {
10154 *return_drop_all_bypass = drop_all_bypass;
10155 }
10156
10157 if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
10158 netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
10159 }
10160
10161 // Pre-process domain for quick matching
10162 struct substring domain_substring = {};
10163 u_int8_t domain_dot_count = 0;
10164 if (info->domain != NULL) {
10165 domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
10166 domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
10167 }
10168
10169 if (return_filter != NULL) {
10170 *return_filter = 0;
10171 }
10172
10173 if (return_route_rule_id_array_count != NULL) {
10174 *return_route_rule_id_array_count = 0;
10175 }
10176
10177 // Do not subject layer-2 filter to NECP policies, return a PASS policy
10178 if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
10179 return &pass_policy;
10180 }
10181
10182 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10183
10184 if (policy_search_array != NULL) {
10185 for (i = 0; policy_search_array[i] != NULL; i++) {
10186 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
10187
10188 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10189 // We've hit a drop all rule
10190 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10191 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
10192 if (return_drop_all_bypass != NULL) {
10193 *return_drop_all_bypass = drop_all_bypass;
10194 }
10195 }
10196 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10197 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
10198 break;
10199 }
10200 }
10201 if (necp_drop_dest_policy.entry_count != 0 &&
10202 necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
10203 // We've hit a drop by destination address rule
10204 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10205 break;
10206 }
10207 if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
10208 // We've hit a drop order for this socket
10209 break;
10210 }
10211 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10212 // Done skipping
10213 skip_order = 0;
10214 skip_session_order = 0;
10215 // If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
10216 if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
10217 *skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10218 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
10219 }
10220 }
10221 if (skip_order) {
10222 if (policy_search_array[i]->order < skip_order) {
10223 // Skip this policy
10224 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10225 // didn't, clear out the return value for skip ID when we are done with each session.'
10226 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10227 skipped_ip_result = true;
10228 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10229 }
10230 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
10231 continue;
10232 } else {
10233 // Done skipping
10234 skip_order = 0;
10235 skip_session_order = 0;
10236 }
10237 } else if (skip_session_order) {
10238 // Skip this policy
10239 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10240 // didn't, clear out the return value for skip ID when we are done with each session.'
10241 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10242 skipped_ip_result = true;
10243 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10244 }
10245 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
10246 continue;
10247 }
10248
10249 if (necp_socket_check_policy(policy_search_array[i],
10250 info->application_id,
10251 info->real_application_id,
10252 info->is_entitled,
10253 info->account_id,
10254 domain_substring,
10255 domain_dot_count,
10256 info->url,
10257 info->pid,
10258 info->pid_version,
10259 info->uid,
10260 info->real_uid,
10261 info->bound_interface_index,
10262 info->traffic_class,
10263 info->protocol,
10264 &info->local_addr,
10265 &info->remote_addr,
10266 required_agent_types,
10267 num_required_agent_types,
10268 info->has_client,
10269 info->client_flags,
10270 info->is_platform_binary,
10271 info->has_system_signed_result,
10272 proc,
10273 pf_tag,
10274 info->scheme_port,
10275 rt,
10276 info->is_loopback,
10277 debug,
10278 info->real_is_platform_binary,
10279 info->bound_interface_flags,
10280 info->bound_interface_eflags,
10281 info->bound_interface_xflags,
10282 info,
10283 info->is_delegated,
10284 so)) {
10285 if (!debug && necp_data_tracing_session_order) {
10286 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10287 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10288 NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
10289 }
10290 }
10291
10292 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
10293 if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
10294 necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
10295 if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
10296 *return_filter = control_unit;
10297 } else {
10298 // Preserve pre-existing connections only if all filters preserve.
10299 bool preserve_bit_off = false;
10300 if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
10301 (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
10302 preserve_bit_off = true;
10303 }
10304 *return_filter |= control_unit;
10305 if (preserve_bit_off == true) {
10306 *return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
10307 }
10308 }
10309 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10310 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);
10311 }
10312 }
10313 continue;
10314 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10315 if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
10316 return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10317 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10318 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);
10319 }
10320 }
10321 continue;
10322 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
10323 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10324 if (netagent_cursor < netagent_array_count_adjusted) {
10325 bool agent_already_present = false;
10326 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10327 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10328 // Already present. Mark the "SCOPED" flag if flags are necessary.
10329 agent_already_present = true;
10330 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
10331 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10332 netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
10333 }
10334 }
10335 }
10336
10337 if (!agent_already_present) {
10338 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10339 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10340 netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
10341 }
10342 netagent_cursor++;
10343 }
10344 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10345 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
10346 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10347 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
10348 policy_search_array[i]->result_parameter.netagent_id);
10349 }
10350 }
10351 continue;
10352 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
10353 bool agent_already_present = false;
10354 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10355 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10356 // Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10357 agent_already_present = true;
10358 netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10359 }
10360 }
10361 if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10362 // If not present, and flags are supported, add an entry with the "REMOVE" flag
10363 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10364 netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10365 netagent_cursor++;
10366 }
10367 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10368 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
10369 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10370 policy_search_array[i]->result_parameter.netagent_id);
10371 }
10372 continue;
10373 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT_TYPE) {
10374 bool agent_already_present = false;
10375 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10376 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10377 // Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10378 agent_already_present = true;
10379 netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10380 }
10381 }
10382 if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10383 // If not present, and flags are supported, add an entry with the "REMOVE" flag
10384 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10385 netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10386 netagent_cursor++;
10387 }
10388 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10389 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove NetagentType %d",
10390 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10391 policy_search_array[i]->result_parameter.netagent_id);
10392 }
10393 continue;
10394 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
10395 u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
10396 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
10397 /* For transparent proxies, accumulate the control unit and continue to the next policy */
10398 if (return_flow_divert_aggregate_unit != NULL) {
10399 *return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
10400 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10401 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);
10402 }
10403 }
10404 continue;
10405 }
10406 }
10407
10408 // Matched policy is a skip. Do skip and continue.
10409 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10410 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
10411 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10412 skip_session_order = policy_search_array[i]->session_order + 1;
10413 if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
10414 *skip_policy_id = policy_search_array[i]->id;
10415 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10416 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);
10417 }
10418 }
10419 continue;
10420 }
10421
10422 // Matched an allow unentitled, which clears any drop order
10423 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
10424 info->drop_order = 0;
10425 continue;
10426 }
10427
10428 // Passed all tests, found a match
10429 matched_policy = policy_search_array[i];
10430 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
10431 break;
10432 }
10433 }
10434 }
10435
10436 if (return_netagent_array != NULL) {
10437 if (return_netagent_use_flags_array != NULL) {
10438 memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
10439 memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
10440 } else {
10441 for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
10442 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
10443 return_netagent_array[netagent_i] = netagent_ids[netagent_i];
10444 } else {
10445 return_netagent_array[netagent_i] = 0;
10446 }
10447 }
10448 }
10449 }
10450
10451 if (return_route_rule_id_array_count != NULL) {
10452 *return_route_rule_id_array_count = route_rule_id_count;
10453 }
10454 return matched_policy;
10455 }
10456
10457 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)10458 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
10459 {
10460 bool found_match = FALSE;
10461 ifaddr_t ifa;
10462 union necp_sockaddr_union address_storage;
10463 int family = AF_INET;
10464
10465 ifnet_head_lock_shared();
10466 ifnet_t interface = ifindex2ifnet[interface_index];
10467 ifnet_head_done();
10468
10469 if (inp == NULL || interface == NULL) {
10470 return FALSE;
10471 }
10472
10473 if (inp->inp_vflag & INP_IPV4) {
10474 family = AF_INET;
10475 } else if (inp->inp_vflag & INP_IPV6) {
10476 family = AF_INET6;
10477 } else {
10478 return FALSE;
10479 }
10480
10481 // Match socket address against interface addresses
10482 ifnet_lock_shared(interface);
10483 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
10484 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
10485 if (address_storage.sa.sa_family != family) {
10486 continue;
10487 }
10488
10489 if (family == AF_INET) {
10490 if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
10491 found_match = TRUE;
10492 break;
10493 }
10494 } else if (family == AF_INET6) {
10495 if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
10496 found_match = TRUE;
10497 break;
10498 }
10499 }
10500 }
10501 }
10502 ifnet_lock_done(interface);
10503
10504 return found_match;
10505 }
10506
10507 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10508 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10509 {
10510 if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10511 proc_t curr_proc = current_proc();
10512 proc_t sock_proc = NULL;
10513 struct socket *so = inp ? inp->inp_socket : NULL;
10514 pid_t socket_pid = (so == NULL) ? 0 :
10515 #if defined(XNU_TARGET_OS_OSX)
10516 so->so_rpid ? so->so_rpid :
10517 #endif
10518 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10519 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10520 sock_proc = proc_find(socket_pid);
10521 }
10522 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10523 if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10524 if (sock_proc) {
10525 proc_rele(sock_proc);
10526 }
10527 return NECP_BYPASS_TYPE_DROP;
10528 }
10529 if (sock_proc) {
10530 proc_rele(sock_proc);
10531 }
10532
10533 if (necp_pass_loopback > 0) {
10534 return NECP_BYPASS_TYPE_LOOPBACK;
10535 }
10536 } else if (necp_is_intcoproc(inp, NULL)) {
10537 return NECP_BYPASS_TYPE_INTCOPROC;
10538 }
10539
10540 return NECP_BYPASS_TYPE_NONE;
10541 }
10542
10543 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10544 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10545 {
10546 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10547 ifnet_t tunnel_interface = NULL;
10548
10549 ifnet_head_lock_shared();
10550 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10551 ifnet_head_done();
10552
10553 if (tunnel_interface != NULL) {
10554 tcp_set_tso(intotcpcb(inp), tunnel_interface);
10555 }
10556 }
10557
10558 static inline void
necp_unscope(struct inpcb * inp)10559 necp_unscope(struct inpcb *inp)
10560 {
10561 // If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10562 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10563 inp->inp_flags &= ~INP_BOUND_IF;
10564 inp->inp_boundifp = NULL;
10565 }
10566 }
10567
10568 static inline void
necp_clear_tunnel(struct inpcb * inp)10569 necp_clear_tunnel(struct inpcb *inp)
10570 {
10571 if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10572 inp->inp_flags &= ~INP_BOUND_IF;
10573 inp->inp_boundifp = NULL;
10574 }
10575 }
10576
10577 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10578 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10579 {
10580 // Verify netagents
10581 for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10582 struct necp_uuid_id_mapping *mapping = NULL;
10583 u_int32_t netagent_id = netagent_ids[netagent_cursor];
10584 if (netagent_id == 0) {
10585 continue;
10586 }
10587 mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
10588 if (mapping != NULL) {
10589 u_int32_t agent_flags = 0;
10590 agent_flags = netagent_get_flags(mapping->uuid);
10591 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10592 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10593 continue;
10594 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10595 if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10596 int trigger_error = 0;
10597 trigger_error = netagent_kernel_trigger(mapping->uuid);
10598 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10599 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);
10600 }
10601 }
10602 return false;
10603 }
10604 }
10605 }
10606 }
10607 return true;
10608 }
10609
10610 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)10611 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10612 {
10613 struct socket *so = NULL;
10614 necp_kernel_policy_filter filter_control_unit = 0;
10615 struct necp_kernel_socket_policy *matched_policy = NULL;
10616 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10617 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10618 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10619 proc_t __single socket_proc = NULL;
10620 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10621
10622 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10623 memset(&netagent_ids, 0, sizeof(netagent_ids));
10624
10625 struct necp_socket_info info = {};
10626
10627 u_int32_t flow_divert_aggregate_unit = 0;
10628
10629 if (inp == NULL) {
10630 return NECP_KERNEL_POLICY_ID_NONE;
10631 }
10632
10633 // Ignore invalid addresses
10634 if (override_local_addr != NULL &&
10635 !necp_address_is_valid(override_local_addr)) {
10636 override_local_addr = NULL;
10637 }
10638 if (override_remote_addr != NULL &&
10639 !necp_address_is_valid(override_remote_addr)) {
10640 override_remote_addr = NULL;
10641 }
10642
10643 so = inp->inp_socket;
10644
10645 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10646
10647 // Don't lock. Possible race condition, but we don't want the performance hit.
10648 if (necp_drop_management_order == 0 &&
10649 (necp_kernel_socket_policies_count == 0 ||
10650 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10651 if (necp_drop_all_order > 0 || drop_order > 0) {
10652 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10653 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10654 inp->inp_policyresult.policy_gencount = 0;
10655 inp->inp_policyresult.app_id = 0;
10656 inp->inp_policyresult.flowhash = 0;
10657 inp->inp_policyresult.results.filter_control_unit = 0;
10658 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10659 inp->inp_policyresult.results.route_rule_id = 0;
10660 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10661 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10662 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10663 } else {
10664 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10665 }
10666 }
10667 return NECP_KERNEL_POLICY_ID_NONE;
10668 }
10669
10670 // Check for loopback exception
10671 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10672 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10673 // Mark socket as a drop
10674 necp_unscope(inp);
10675 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10676 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10677 inp->inp_policyresult.policy_gencount = 0;
10678 inp->inp_policyresult.app_id = 0;
10679 inp->inp_policyresult.flowhash = 0;
10680 inp->inp_policyresult.results.filter_control_unit = 0;
10681 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10682 inp->inp_policyresult.results.route_rule_id = 0;
10683 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10684 return NECP_KERNEL_POLICY_ID_NONE;
10685 }
10686
10687 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10688 // Mark socket as a pass
10689 necp_unscope(inp);
10690 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10691 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10692 inp->inp_policyresult.policy_gencount = 0;
10693 inp->inp_policyresult.app_id = 0;
10694 inp->inp_policyresult.flowhash = 0;
10695 inp->inp_policyresult.results.filter_control_unit = 0;
10696 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10697 inp->inp_policyresult.results.route_rule_id = 0;
10698 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10699 return NECP_KERNEL_POLICY_ID_NONE;
10700 }
10701
10702 // Lock
10703 lck_rw_lock_shared(&necp_kernel_policy_lock);
10704 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);
10705
10706 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10707 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10708
10709 // Check info
10710 u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10711 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10712 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10713 inp->inp_policyresult.flowhash == flowhash) {
10714 // If already matched this socket on this generation of table, skip
10715
10716 if (info.soflow_entry != NULL) {
10717 soflow_free_flow(info.soflow_entry);
10718 }
10719
10720 // Unlock
10721 lck_rw_done(&necp_kernel_policy_lock);
10722
10723 if (socket_proc) {
10724 proc_rele(socket_proc);
10725 }
10726
10727 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10728 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10729 inp->inp_socket, info.bound_interface_index, info.protocol,
10730 inp->inp_policyresult.policy_id,
10731 inp->inp_policyresult.results.result,
10732 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10733 }
10734 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10735 return inp->inp_policyresult.policy_id;
10736 }
10737
10738 inp->inp_policyresult.app_id = info.application_id;
10739
10740 // Match socket to policy
10741 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10742 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10743 size_t route_rule_id_array_count = 0;
10744
10745 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10746 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)],
10747 &info,
10748 &filter_control_unit,
10749 route_rule_id_array,
10750 &route_rule_id_array_count,
10751 MAX_AGGREGATE_ROUTE_RULES,
10752 netagent_ids,
10753 NECP_MAX_NETAGENTS,
10754 NULL,
10755 0,
10756 NULL,
10757 0,
10758 effective_proc,
10759 0,
10760 &skip_policy_id,
10761 inp->inp_route.ro_rt,
10762 &drop_dest_policy_result,
10763 &drop_all_bypass,
10764 &flow_divert_aggregate_unit,
10765 so,
10766 debug);
10767
10768 // Check for loopback exception again after the policy match
10769 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10770 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10771 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10772 // Mark socket as a pass
10773 necp_unscope(inp);
10774 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10775 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10776 inp->inp_policyresult.policy_gencount = 0;
10777 inp->inp_policyresult.app_id = 0;
10778 inp->inp_policyresult.flowhash = 0;
10779 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10780 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10781 inp->inp_policyresult.results.route_rule_id = 0;
10782 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10783 if (info.soflow_entry != NULL) {
10784 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10785 info.soflow_entry->soflow_policies_gencount = 0;
10786 soflow_free_flow(info.soflow_entry);
10787 }
10788
10789 // Unlock
10790 lck_rw_done(&necp_kernel_policy_lock);
10791
10792 if (socket_proc) {
10793 proc_rele(socket_proc);
10794 }
10795
10796 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10797 return NECP_KERNEL_POLICY_ID_NONE;
10798 }
10799
10800 // Verify netagents
10801 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10802 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10803 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);
10804 }
10805
10806 // Mark socket as a drop if required agent is not active
10807 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10808 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10809 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10810 inp->inp_policyresult.flowhash = flowhash;
10811 inp->inp_policyresult.results.filter_control_unit = 0;
10812 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10813 inp->inp_policyresult.results.route_rule_id = 0;
10814 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10815 if (info.soflow_entry != NULL) {
10816 info.soflow_entry->soflow_filter_control_unit = 0;
10817 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10818 soflow_free_flow(info.soflow_entry);
10819 }
10820
10821 // Unlock
10822 lck_rw_done(&necp_kernel_policy_lock);
10823
10824 if (socket_proc) {
10825 proc_rele(socket_proc);
10826 }
10827
10828 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);
10829 return NECP_KERNEL_POLICY_ID_NONE;
10830 }
10831
10832 u_int32_t route_rule_id = 0;
10833 if (route_rule_id_array_count == 1) {
10834 route_rule_id = route_rule_id_array[0];
10835 } else if (route_rule_id_array_count > 1) {
10836 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10837 }
10838
10839 bool reset_tcp_tunnel_interface = false;
10840 bool send_local_network_denied_event = false;
10841 if (matched_policy) {
10842 // For PASS policy result, clear previous rescope / tunnel inteface
10843 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10844 (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10845 necp_unscope(inp);
10846 necp_clear_tunnel(inp);
10847 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10848 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10849 }
10850 }
10851 matched_policy_id = matched_policy->id;
10852 inp->inp_policyresult.policy_id = matched_policy->id;
10853 inp->inp_policyresult.skip_policy_id = skip_policy_id;
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 = filter_control_unit;
10857 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10858 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10859 inp->inp_policyresult.results.result = matched_policy->result;
10860 memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10861 if (info.soflow_entry != NULL) {
10862 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10863 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10864 }
10865
10866 if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10867 inp->inp_policyresult.app_id = info.real_application_id;
10868 }
10869
10870 if (necp_socket_is_connected(inp) &&
10871 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10872 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10873 NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10874 sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10875 } else if (necp_socket_is_connected(inp) &&
10876 matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10877 info.protocol == IPPROTO_TCP) {
10878 // Reset TCP socket interface based parameters if tunnel policy changes
10879 reset_tcp_tunnel_interface = true;
10880 }
10881
10882 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10883 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);
10884 }
10885
10886 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10887 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10888 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10889 // Trigger the event that we dropped due to a local network policy
10890 send_local_network_denied_event = true;
10891 }
10892 } else {
10893 bool drop_all = false;
10894 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10895 // Mark socket as a drop if set
10896 drop_all = true;
10897 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10898 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10899 }
10900 }
10901
10902 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10903 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);
10904 if (flow_divert_control_unit != 0) {
10905 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10906 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10907 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10908 inp->inp_policyresult.flowhash = flowhash;
10909 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10910 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10911 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10912 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10913 inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10914 if (info.soflow_entry != NULL) {
10915 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10916 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10917 }
10918 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);
10919 } else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10920 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10921 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10922 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10923 inp->inp_policyresult.flowhash = flowhash;
10924 inp->inp_policyresult.results.filter_control_unit = 0;
10925 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10926 inp->inp_policyresult.results.route_rule_id = 0;
10927 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10928 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);
10929 if (info.soflow_entry != NULL) {
10930 info.soflow_entry->soflow_filter_control_unit = 0;
10931 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10932 }
10933 } else {
10934 // Mark non-matching socket so we don't re-check it
10935 necp_unscope(inp);
10936 if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10937 necp_clear_tunnel(inp);
10938 }
10939 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10940 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);
10941 }
10942 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10943 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10944 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10945 inp->inp_policyresult.flowhash = flowhash;
10946 inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10947 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10948 inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10949 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10950 if (info.soflow_entry != NULL) {
10951 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10952 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10953 }
10954 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10955 }
10956 }
10957
10958 if (necp_check_missing_client_drop(effective_proc, &info) ||
10959 necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10960 // Mark as drop
10961 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10962 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10963 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10964 inp->inp_policyresult.flowhash = flowhash;
10965 inp->inp_policyresult.results.filter_control_unit = 0;
10966 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10967 inp->inp_policyresult.results.route_rule_id = 0;
10968 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10969 if (info.soflow_entry != NULL) {
10970 info.soflow_entry->soflow_filter_control_unit = 0;
10971 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10972 }
10973 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10974 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10975 }
10976 }
10977
10978 if (info.soflow_entry != NULL) {
10979 soflow_free_flow(info.soflow_entry);
10980 }
10981
10982 // Unlock
10983 lck_rw_done(&necp_kernel_policy_lock);
10984
10985 if (reset_tcp_tunnel_interface) {
10986 // Update MSS when not holding the policy lock to avoid recursive locking
10987 tcp_mtudisc(inp, 0);
10988
10989 // Update TSO flag based on the tunnel interface
10990 necp_socket_ip_tunnel_tso(inp);
10991 }
10992
10993 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10994 inp->inp_policyresult.network_denied_notifies++;
10995 #if defined(XNU_TARGET_OS_OSX)
10996 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10997 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10998 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10999 NETPOLICY_NETWORKTYPE_LOCAL);
11000 #else
11001 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
11002 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
11003 NETPOLICY_NETWORKTYPE_LOCAL);
11004 #endif
11005 }
11006
11007 if (socket_proc) {
11008 proc_rele(socket_proc);
11009 }
11010
11011 return matched_policy_id;
11012 }
11013
11014 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)11015 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)
11016 {
11017 u_int32_t bound_interface_flags = 0;
11018 u_int32_t bound_interface_eflags = 0;
11019 u_int32_t bound_interface_xflags = 0;
11020
11021 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
11022 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
11023 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
11024 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
11025 "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
11026 cond_bound_interface_index, bound_interface_index);
11027 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
11028 if (bound_interface_index == cond_bound_interface_index) {
11029 // No match, matches forbidden interface
11030 return FALSE;
11031 }
11032 } else {
11033 if (bound_interface_index != cond_bound_interface_index) {
11034 // No match, does not match required interface
11035 return FALSE;
11036 }
11037 }
11038 }
11039 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
11040 if (bound_interface_index != IFSCOPE_NONE) {
11041 ifnet_head_lock_shared();
11042 ifnet_t interface = ifindex2ifnet[bound_interface_index];
11043 if (interface != NULL) {
11044 bound_interface_flags = interface->if_flags;
11045 bound_interface_eflags = interface->if_eflags;
11046 bound_interface_xflags = interface->if_xflags;
11047 }
11048 ifnet_head_done();
11049 }
11050
11051 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
11052 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
11053 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
11054 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
11055 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
11056 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
11057 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
11058 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
11059 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
11060 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
11061 // No match, matches some forbidden interface flags
11062 return FALSE;
11063 }
11064 } else {
11065 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
11066 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
11067 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
11068 // No match, does not match some required interface xflags
11069 return FALSE;
11070 }
11071 }
11072 }
11073 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
11074 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
11075 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
11076 if (bound_interface_index != 0) {
11077 // No match, requires a non-bound packet
11078 return FALSE;
11079 }
11080 }
11081 }
11082
11083 if (kernel_policy->condition_mask == 0) {
11084 return TRUE;
11085 }
11086
11087 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
11088 necp_kernel_policy_id matched_policy_id =
11089 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
11090 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
11091 "NECP_KERNEL_CONDITION_POLICY_ID",
11092 kernel_policy->cond_policy_id, 0, 0,
11093 matched_policy_id, socket_policy_id, socket_skip_policy_id);
11094 if (matched_policy_id != kernel_policy->cond_policy_id) {
11095 // No match, does not match required id
11096 return FALSE;
11097 }
11098 }
11099
11100 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
11101 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
11102 "NECP_KERNEL_CONDITION_LAST_INTERFACE",
11103 kernel_policy->cond_last_interface_index, last_interface_index);
11104 if (last_interface_index != kernel_policy->cond_last_interface_index) {
11105 return FALSE;
11106 }
11107 }
11108
11109 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11110 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
11111 "NECP_KERNEL_CONDITION_PROTOCOL",
11112 kernel_policy->cond_protocol, protocol);
11113 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11114 if (protocol == kernel_policy->cond_protocol) {
11115 // No match, matches forbidden protocol
11116 return FALSE;
11117 }
11118 } else {
11119 if (protocol != kernel_policy->cond_protocol) {
11120 // No match, does not match required protocol
11121 return FALSE;
11122 }
11123 }
11124 }
11125
11126 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11127 bool is_local = FALSE;
11128 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
11129
11130 if (rt != NULL) {
11131 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
11132 } else {
11133 is_local = necp_is_route_local(remote, include_local_addresses);
11134 }
11135 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);
11136 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11137 if (is_local) {
11138 // Match local-networks, fail
11139 return FALSE;
11140 }
11141 } else {
11142 if (!is_local) {
11143 // Either no route to validate or no match for local networks
11144 return FALSE;
11145 }
11146 }
11147 }
11148
11149 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
11150 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11151 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
11152 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
11153 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11154 if (inRange) {
11155 return FALSE;
11156 }
11157 } else {
11158 if (!inRange) {
11159 return FALSE;
11160 }
11161 }
11162 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11163 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
11164 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
11165 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11166 if (inSubnet) {
11167 return FALSE;
11168 }
11169 } else {
11170 if (!inSubnet) {
11171 return FALSE;
11172 }
11173 }
11174 }
11175 }
11176
11177 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
11178 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11179 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
11180 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
11181 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11182 if (inRange) {
11183 return FALSE;
11184 }
11185 } else {
11186 if (!inRange) {
11187 return FALSE;
11188 }
11189 }
11190 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11191 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
11192 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
11193 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11194 if (inSubnet) {
11195 return FALSE;
11196 }
11197 } else {
11198 if (!inSubnet) {
11199 return FALSE;
11200 }
11201 }
11202 }
11203 }
11204
11205 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11206 u_int16_t remote_port = 0;
11207 if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
11208 remote_port = SIN(remote)->sin_port;
11209 }
11210 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
11211 "NECP_KERNEL_CONDITION_SCHEME_PORT",
11212 0, remote_port);
11213 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11214 if (kernel_policy->cond_scheme_port == remote_port) {
11215 return FALSE;
11216 }
11217 } else {
11218 if (kernel_policy->cond_scheme_port != remote_port) {
11219 return FALSE;
11220 }
11221 }
11222 }
11223
11224 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11225 bool tags_matched = false;
11226 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
11227 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
11228 kernel_policy->cond_packet_filter_tags, pf_tag);
11229 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
11230 if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
11231 tags_matched = true;
11232 }
11233
11234 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11235 if (tags_matched) {
11236 return FALSE;
11237 }
11238 } else {
11239 if (!tags_matched) {
11240 return FALSE;
11241 }
11242 }
11243 }
11244 }
11245
11246 return TRUE;
11247 }
11248
11249 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)11250 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)
11251 {
11252 u_int32_t skip_order = 0;
11253 u_int32_t skip_session_order = 0;
11254 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11255 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)];
11256 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11257 size_t route_rule_id_count = 0;
11258 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11259 if (return_drop_all_bypass != NULL) {
11260 *return_drop_all_bypass = drop_all_bypass;
11261 }
11262
11263 if (return_route_rule_id != NULL) {
11264 *return_route_rule_id = 0;
11265 }
11266
11267 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11268
11269 if (policy_search_array != NULL) {
11270 for (int i = 0; policy_search_array[i] != NULL; i++) {
11271 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
11272 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
11273 // We've hit a drop all rule
11274 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11275 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11276 if (return_drop_all_bypass != NULL) {
11277 *return_drop_all_bypass = drop_all_bypass;
11278 }
11279 }
11280 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11281 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
11282 break;
11283 }
11284 }
11285 if (necp_drop_dest_policy.entry_count > 0 &&
11286 necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
11287 // We've hit a drop by destination address rule
11288 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
11289 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
11290 break;
11291 }
11292 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
11293 // Done skipping
11294 skip_order = 0;
11295 skip_session_order = 0;
11296 }
11297 if (skip_order) {
11298 if (policy_search_array[i]->order < skip_order) {
11299 // Skip this policy
11300 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
11301 continue;
11302 } else {
11303 // Done skipping
11304 skip_order = 0;
11305 skip_session_order = 0;
11306 }
11307 } else if (skip_session_order) {
11308 // Skip this policy
11309 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
11310 continue;
11311 }
11312
11313 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)) {
11314 if (!debug && necp_data_tracing_session_order) {
11315 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
11316 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
11317 NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
11318 }
11319 }
11320
11321 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
11322 if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
11323 route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
11324 }
11325 continue;
11326 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
11327 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
11328 skip_session_order = policy_search_array[i]->session_order + 1;
11329 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
11330 continue;
11331 }
11332
11333 // Passed all tests, found a match
11334 matched_policy = policy_search_array[i];
11335 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
11336 break;
11337 }
11338 }
11339 }
11340
11341 if (route_rule_id_count == 1) {
11342 *return_route_rule_id = route_rule_id_array[0];
11343 } else if (route_rule_id_count > 1) {
11344 *return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11345 }
11346
11347 return matched_policy;
11348 }
11349
11350 static inline bool
necp_output_bypass(struct mbuf * packet)11351 necp_output_bypass(struct mbuf *packet)
11352 {
11353 if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
11354 return true;
11355 }
11356 if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
11357 return true;
11358 }
11359 if (necp_is_intcoproc(NULL, packet)) {
11360 return true;
11361 }
11362 return false;
11363 }
11364
11365 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)11366 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
11367 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11368 {
11369 struct ip *ip = NULL;
11370 int hlen = sizeof(struct ip);
11371 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11372 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11373 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11374 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11375 u_int16_t protocol = 0;
11376 u_int32_t bound_interface_index = 0;
11377 u_int32_t last_interface_index = 0;
11378 union necp_sockaddr_union local_addr = { };
11379 union necp_sockaddr_union remote_addr = { };
11380 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11381 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11382 u_int16_t pf_tag = 0;
11383
11384 if (result) {
11385 *result = 0;
11386 }
11387
11388 if (result_parameter) {
11389 memset(result_parameter, 0, sizeof(*result_parameter));
11390 }
11391
11392 if (packet == NULL) {
11393 return NECP_KERNEL_POLICY_ID_NONE;
11394 }
11395
11396 socket_policy_id = necp_get_policy_id_from_packet(packet);
11397 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11398 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11399
11400 // Exit early for an empty list
11401 // Don't lock. Possible race condition, but we don't want the performance hit.
11402 if (necp_kernel_ip_output_policies_count == 0 ||
11403 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
11404 if (necp_drop_all_order > 0) {
11405 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11406 if (result) {
11407 if (necp_output_bypass(packet)) {
11408 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11409 } else {
11410 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11411 }
11412 }
11413 }
11414
11415 return matched_policy_id;
11416 }
11417
11418 // Check for loopback exception
11419 if (necp_output_bypass(packet)) {
11420 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11421 if (result) {
11422 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11423 }
11424 return matched_policy_id;
11425 }
11426
11427 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11428
11429 // Process packet to get relevant fields
11430 ip = mtod(packet, struct ip *);
11431 #ifdef _IP_VHL
11432 hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
11433 #else
11434 hlen = ip->ip_hl << 2;
11435 #endif
11436
11437 protocol = ip->ip_p;
11438
11439 if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
11440 (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
11441 ipoa->ipoa_boundif != IFSCOPE_NONE) {
11442 bound_interface_index = ipoa->ipoa_boundif;
11443 }
11444
11445 local_addr.sin.sin_family = AF_INET;
11446 local_addr.sin.sin_len = sizeof(struct sockaddr_in);
11447 memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
11448
11449 remote_addr.sin.sin_family = AF_INET;
11450 remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
11451 memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
11452
11453 switch (protocol) {
11454 case IPPROTO_TCP: {
11455 struct tcphdr th;
11456 if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
11457 m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
11458 SIN(&local_addr)->sin_port = th.th_sport;
11459 SIN(&remote_addr)->sin_port = th.th_dport;
11460 }
11461 break;
11462 }
11463 case IPPROTO_UDP: {
11464 struct udphdr uh;
11465 if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
11466 m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
11467 SIN(&local_addr)->sin_port = uh.uh_sport;
11468 SIN(&remote_addr)->sin_port = uh.uh_dport;
11469 }
11470 break;
11471 }
11472 default: {
11473 SIN(&local_addr)->sin_port = 0;
11474 SIN(&remote_addr)->sin_port = 0;
11475 break;
11476 }
11477 }
11478
11479 // Match packet to policy
11480 lck_rw_lock_shared(&necp_kernel_policy_lock);
11481 u_int32_t route_rule_id = 0;
11482
11483 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11484 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
11485
11486 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);
11487 if (matched_policy) {
11488 matched_policy_id = matched_policy->id;
11489 if (result) {
11490 *result = matched_policy->result;
11491 }
11492
11493 if (result_parameter) {
11494 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11495 }
11496
11497 if (route_rule_id != 0 &&
11498 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11499 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11500 }
11501
11502 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11503 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);
11504 }
11505 } else {
11506 bool drop_all = false;
11507 /*
11508 * Apply drop-all only to packets which have never matched a primary policy (check
11509 * if the packet saved policy id is none or falls within the socket policy id range).
11510 */
11511 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11512 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11513 drop_all = true;
11514 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11515 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11516 }
11517 }
11518 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11519 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11520 if (result) {
11521 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11522 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
11523 }
11524 } else if (route_rule_id != 0 &&
11525 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11526 // If we matched a route rule, mark it
11527 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11528 }
11529 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11530 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);
11531 }
11532 }
11533
11534 lck_rw_done(&necp_kernel_policy_lock);
11535
11536 return matched_policy_id;
11537 }
11538
11539 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)11540 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11541 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11542 {
11543 struct ip6_hdr *ip6 = NULL;
11544 int next = -1;
11545 int offset = 0;
11546 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11547 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11548 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11549 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11550 u_int16_t protocol = 0;
11551 u_int32_t bound_interface_index = 0;
11552 u_int32_t last_interface_index = 0;
11553 union necp_sockaddr_union local_addr = { };
11554 union necp_sockaddr_union remote_addr = { };
11555 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11556 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11557 u_int16_t pf_tag = 0;
11558
11559 if (result) {
11560 *result = 0;
11561 }
11562
11563 if (result_parameter) {
11564 memset(result_parameter, 0, sizeof(*result_parameter));
11565 }
11566
11567 if (packet == NULL) {
11568 return NECP_KERNEL_POLICY_ID_NONE;
11569 }
11570
11571 socket_policy_id = necp_get_policy_id_from_packet(packet);
11572 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11573 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11574
11575 // Exit early for an empty list
11576 // Don't lock. Possible race condition, but we don't want the performance hit.
11577 if (necp_drop_management_order == 0 &&
11578 (necp_kernel_ip_output_policies_count == 0 ||
11579 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11580 if (necp_drop_all_order > 0) {
11581 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11582 if (result) {
11583 if (necp_output_bypass(packet)) {
11584 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11585 } else {
11586 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11587 }
11588 }
11589 }
11590
11591 return matched_policy_id;
11592 }
11593
11594 // Check for loopback exception
11595 if (necp_output_bypass(packet)) {
11596 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11597 if (result) {
11598 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11599 }
11600 return matched_policy_id;
11601 }
11602
11603 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11604
11605 // Process packet to get relevant fields
11606 ip6 = mtod(packet, struct ip6_hdr *);
11607
11608 if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11609 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11610 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11611 bound_interface_index = ip6oa->ip6oa_boundif;
11612 }
11613
11614 SIN6(&local_addr)->sin6_family = AF_INET6;
11615 SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11616 memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11617
11618 SIN6(&remote_addr)->sin6_family = AF_INET6;
11619 SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11620 memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11621
11622 offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11623 if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11624 protocol = next;
11625 switch (protocol) {
11626 case IPPROTO_TCP: {
11627 struct tcphdr th;
11628 if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11629 m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11630 SIN6(&local_addr)->sin6_port = th.th_sport;
11631 SIN6(&remote_addr)->sin6_port = th.th_dport;
11632 }
11633 break;
11634 }
11635 case IPPROTO_UDP: {
11636 struct udphdr uh;
11637 if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11638 m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11639 SIN6(&local_addr)->sin6_port = uh.uh_sport;
11640 SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11641 }
11642 break;
11643 }
11644 default: {
11645 SIN6(&local_addr)->sin6_port = 0;
11646 SIN6(&remote_addr)->sin6_port = 0;
11647 break;
11648 }
11649 }
11650 }
11651
11652 // Match packet to policy
11653 lck_rw_lock_shared(&necp_kernel_policy_lock);
11654 u_int32_t route_rule_id = 0;
11655
11656 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11657 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11658
11659 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);
11660 if (matched_policy) {
11661 matched_policy_id = matched_policy->id;
11662 if (result) {
11663 *result = matched_policy->result;
11664 }
11665
11666 if (result_parameter) {
11667 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11668 }
11669
11670 if (route_rule_id != 0 &&
11671 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11672 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11673 }
11674
11675 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11676 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);
11677 }
11678 } else {
11679 bool drop_all = false;
11680 /*
11681 * Apply drop-all only to packets which have never matched a primary policy (check
11682 * if the packet saved policy id is none or falls within the socket policy id range).
11683 */
11684 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11685 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11686 drop_all = true;
11687 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11688 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11689 }
11690 }
11691 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11692 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11693 if (result) {
11694 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11695 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11696 }
11697 } else if (route_rule_id != 0 &&
11698 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11699 // If we matched a route rule, mark it
11700 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11701 }
11702 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11703 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);
11704 }
11705 }
11706
11707 lck_rw_done(&necp_kernel_policy_lock);
11708
11709 return matched_policy_id;
11710 }
11711
11712 // Utilities
11713 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11714 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11715 {
11716 int cmp = 0;
11717
11718 if (addr == NULL || range_start == NULL || range_end == NULL) {
11719 return FALSE;
11720 }
11721
11722 /* Must be greater than or equal to start */
11723 cmp = necp_addr_compare(addr, range_start, 1);
11724 if (cmp != 0 && cmp != 1) {
11725 return FALSE;
11726 }
11727
11728 /* Must be less than or equal to end */
11729 cmp = necp_addr_compare(addr, range_end, 1);
11730 if (cmp != 0 && cmp != -1) {
11731 return FALSE;
11732 }
11733
11734 return TRUE;
11735 }
11736
11737 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)11738 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11739 {
11740 int cmp = 0;
11741
11742 if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11743 return FALSE;
11744 }
11745
11746 /* Must be greater than or equal to start */
11747 cmp = necp_addr_compare(inner_range_start, range_start, 1);
11748 if (cmp != 0 && cmp != 1) {
11749 return FALSE;
11750 }
11751
11752 /* Must be less than or equal to end */
11753 cmp = necp_addr_compare(inner_range_end, range_end, 1);
11754 if (cmp != 0 && cmp != -1) {
11755 return FALSE;
11756 }
11757
11758 return TRUE;
11759 }
11760
11761 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11762 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11763 {
11764 if (addr == NULL || subnet_addr == NULL) {
11765 return FALSE;
11766 }
11767
11768 if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11769 return FALSE;
11770 }
11771
11772 switch (addr->sa_family) {
11773 case AF_INET: {
11774 if (satosin(subnet_addr)->sin_port != 0 &&
11775 satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11776 return FALSE;
11777 }
11778 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11779 }
11780 case AF_INET6: {
11781 if (satosin6(subnet_addr)->sin6_port != 0 &&
11782 satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11783 return FALSE;
11784 }
11785 if (satosin6(addr)->sin6_scope_id &&
11786 satosin6(subnet_addr)->sin6_scope_id &&
11787 satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11788 return FALSE;
11789 }
11790 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11791 }
11792 default: {
11793 return FALSE;
11794 }
11795 }
11796
11797 return FALSE;
11798 }
11799
11800 /*
11801 * Return values:
11802 * -1: sa1 < sa2
11803 * 0: sa1 == sa2
11804 * 1: sa1 > sa2
11805 * 2: Not comparable or error
11806 */
11807 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11808 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11809 {
11810 int result = 0;
11811 int port_result = 0;
11812
11813 if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11814 return 2;
11815 }
11816
11817 if (sa1->sa_len == 0) {
11818 return 0;
11819 }
11820
11821 switch (sa1->sa_family) {
11822 case AF_INET: {
11823 if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11824 return 2;
11825 }
11826
11827 result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11828
11829 if (check_port) {
11830 if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11831 port_result = -1;
11832 } else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11833 port_result = 1;
11834 }
11835
11836 if (result == 0) {
11837 result = port_result;
11838 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11839 return 2;
11840 }
11841 }
11842
11843 break;
11844 }
11845 case AF_INET6: {
11846 if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11847 return 2;
11848 }
11849
11850 if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11851 return 2;
11852 }
11853
11854 result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11855
11856 if (check_port) {
11857 if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11858 port_result = -1;
11859 } else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11860 port_result = 1;
11861 }
11862
11863 if (result == 0) {
11864 result = port_result;
11865 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11866 return 2;
11867 }
11868 }
11869
11870 break;
11871 }
11872 default: {
11873 result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11874 break;
11875 }
11876 }
11877
11878 if (result < 0) {
11879 result = (-1);
11880 } else if (result > 0) {
11881 result = (1);
11882 }
11883
11884 return result;
11885 }
11886
11887 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11888 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11889 {
11890 u_int8_t mask;
11891
11892 /* Handle null pointers */
11893 if (p1 == NULL || p2 == NULL) {
11894 return p1 == p2;
11895 }
11896
11897 while (bits >= 8) {
11898 if (*p1++ != *p2++) {
11899 return FALSE;
11900 }
11901 bits -= 8;
11902 }
11903
11904 if (bits > 0) {
11905 mask = ~((1 << (8 - bits)) - 1);
11906 if ((*p1 & mask) != (*p2 & mask)) {
11907 return FALSE;
11908 }
11909 }
11910 return TRUE;
11911 }
11912
11913 static bool
necp_addr_is_empty(struct sockaddr * addr)11914 necp_addr_is_empty(struct sockaddr *addr)
11915 {
11916 if (addr == NULL) {
11917 return TRUE;
11918 }
11919
11920 if (addr->sa_len == 0) {
11921 return TRUE;
11922 }
11923
11924 switch (addr->sa_family) {
11925 case AF_INET: {
11926 static struct sockaddr_in ipv4_empty_address = {
11927 .sin_len = sizeof(struct sockaddr_in),
11928 .sin_family = AF_INET,
11929 .sin_port = 0,
11930 .sin_addr = { .s_addr = 0 }, // 0.0.0.0
11931 .sin_zero = {0},
11932 };
11933 if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11934 return TRUE;
11935 } else {
11936 return FALSE;
11937 }
11938 }
11939 case AF_INET6: {
11940 static struct sockaddr_in6 ipv6_empty_address = {
11941 .sin6_len = sizeof(struct sockaddr_in6),
11942 .sin6_family = AF_INET6,
11943 .sin6_port = 0,
11944 .sin6_flowinfo = 0,
11945 .sin6_addr = IN6ADDR_ANY_INIT, // ::
11946 .sin6_scope_id = 0,
11947 };
11948 if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11949 return TRUE;
11950 } else {
11951 return FALSE;
11952 }
11953 }
11954 default:
11955 return FALSE;
11956 }
11957
11958 return FALSE;
11959 }
11960
11961 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)11962 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)
11963 {
11964 bool qos_marking = FALSE;
11965 int exception_index = 0;
11966 struct necp_route_rule *route_rule = NULL;
11967
11968 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11969 if (route_rule == NULL) {
11970 qos_marking = FALSE;
11971 goto done;
11972 }
11973
11974 if (route_rule->match_netagent_id != 0) {
11975 if (netagent_array == NULL || netagent_array_count == 0) {
11976 // No agents, ignore rule
11977 goto done;
11978 }
11979 bool found_match = FALSE;
11980 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11981 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11982 found_match = TRUE;
11983 break;
11984 }
11985 }
11986 if (!found_match) {
11987 // Agents don't match, ignore rule
11988 goto done;
11989 }
11990 }
11991
11992 qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11993
11994 if (ifp == NULL) {
11995 goto done;
11996 }
11997
11998 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11999 if (route_rule->exception_if_indices[exception_index] == 0) {
12000 break;
12001 }
12002 if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
12003 continue;
12004 }
12005 if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
12006 qos_marking = TRUE;
12007 if (necp_debug > 2) {
12008 NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
12009 route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
12010 }
12011 goto done;
12012 }
12013 }
12014
12015 if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
12016 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
12017 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
12018 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
12019 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
12020 (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_ULTRA_CONSTRAINED(ifp)) ||
12021 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
12022 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
12023 qos_marking = TRUE;
12024 if (necp_debug > 2) {
12025 NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d UlCn:%d for Rule %d Allowed %d",
12026 route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
12027 route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action,
12028 route_rule->ultra_constrained_action, route_rule_id, qos_marking);
12029 }
12030 goto done;
12031 }
12032 done:
12033 if (necp_debug > 1) {
12034 NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
12035 route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
12036 }
12037 return qos_marking;
12038 }
12039
12040 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)12041 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)
12042 {
12043 bool new_qos_marking = old_qos_marking;
12044 struct ifnet *ifp = interface;
12045
12046 if (net_qos_policy_restricted == 0) {
12047 return new_qos_marking;
12048 }
12049
12050 /*
12051 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
12052 */
12053 if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
12054 return new_qos_marking;
12055 }
12056
12057 lck_rw_lock_shared(&necp_kernel_policy_lock);
12058
12059 if (ifp == NULL && route != NULL) {
12060 ifp = route->rt_ifp;
12061 }
12062 /*
12063 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
12064 */
12065 if (ifp == NULL || route_rule_id == 0) {
12066 new_qos_marking = FALSE;
12067 goto done;
12068 }
12069
12070 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12071 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12072 if (aggregate_route_rule != NULL) {
12073 int index = 0;
12074 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12075 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12076 if (sub_route_rule_id == 0) {
12077 break;
12078 }
12079 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
12080 if (new_qos_marking == TRUE) {
12081 break;
12082 }
12083 }
12084 }
12085 } else {
12086 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
12087 }
12088 /*
12089 * Now that we have an interface we remember the gencount
12090 */
12091 *qos_marking_gencount = necp_kernel_socket_policies_gencount;
12092
12093 done:
12094 lck_rw_done(&necp_kernel_policy_lock);
12095 return new_qos_marking;
12096 }
12097
12098 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)12099 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
12100 {
12101 bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
12102
12103 if (net_qos_policy_restricted == 0) {
12104 return;
12105 }
12106 if (inp->inp_socket == NULL) {
12107 return;
12108 }
12109 if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
12110 return;
12111 }
12112
12113 qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
12114
12115 if (qos_marking == TRUE) {
12116 inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
12117 } else {
12118 inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
12119 }
12120 }
12121
12122 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)12123 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
12124 {
12125 if (ifp != NULL &&
12126 (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12127 ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12128 return true;
12129 }
12130 if (delegated_ifp != NULL &&
12131 (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12132 delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12133 return true;
12134 }
12135 return false;
12136 }
12137
12138 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,bool * ultra_constrained_denied)12139 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,
12140 u_int32_t route_rule_id, u_int32_t *interface_type_denied, bool *ultra_constrained_denied)
12141 {
12142 bool default_is_allowed = TRUE;
12143 u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
12144 int exception_index = 0;
12145 struct ifnet *delegated_ifp = NULL;
12146 struct necp_route_rule *route_rule = NULL;
12147
12148 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12149 if (route_rule == NULL) {
12150 return TRUE;
12151 }
12152
12153 if (route_rule->match_netagent_id != 0) {
12154 if (netagent_array == NULL || netagent_array_count == 0) {
12155 // No agents, ignore rule
12156 return TRUE;
12157 }
12158 bool found_match = FALSE;
12159 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12160 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12161 found_match = TRUE;
12162 break;
12163 }
12164 }
12165 if (!found_match) {
12166 // Agents don't match, ignore rule
12167 return TRUE;
12168 }
12169 }
12170
12171 default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
12172 if (ifp == NULL && route != NULL) {
12173 ifp = route->rt_ifp;
12174 }
12175 if (ifp == NULL) {
12176 if (necp_debug > 1 && !default_is_allowed) {
12177 NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12178 }
12179 return default_is_allowed;
12180 }
12181
12182 delegated_ifp = ifp->if_delegated.ifp;
12183 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12184 if (route_rule->exception_if_indices[exception_index] == 0) {
12185 break;
12186 }
12187 if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
12188 (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
12189 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12190 const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
12191 if (necp_debug > 1 && lqm_abort) {
12192 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
12193 route_rule->exception_if_indices[exception_index], route_rule_id);
12194 }
12195 return false;
12196 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
12197 if (necp_debug > 1) {
12198 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));
12199 }
12200 if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
12201 *interface_type_denied = route_rule->effective_type;
12202 }
12203 return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
12204 }
12205 }
12206 }
12207
12208 if (IFNET_IS_CELLULAR(ifp)) {
12209 if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12210 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12211 if (interface_type_denied != NULL) {
12212 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12213 if (route_rule->effective_type != 0) {
12214 *interface_type_denied = route_rule->effective_type;
12215 }
12216 }
12217 // Mark aggregate action as deny
12218 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12219 }
12220 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
12221 if (interface_type_denied != NULL) {
12222 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12223 if (route_rule->effective_type != 0) {
12224 *interface_type_denied = route_rule->effective_type;
12225 }
12226 }
12227 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12228 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12229 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
12230 // Deny wins if there is a conflict
12231 type_aggregate_action = route_rule->cellular_action;
12232 }
12233 }
12234 }
12235
12236 if (IFNET_IS_WIFI(ifp)) {
12237 if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12238 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12239 if (interface_type_denied != NULL) {
12240 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12241 if (route_rule->effective_type != 0) {
12242 *interface_type_denied = route_rule->effective_type;
12243 }
12244 }
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->wifi_action)) {
12249 if (interface_type_denied != NULL) {
12250 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12251 if (route_rule->effective_type != 0) {
12252 *interface_type_denied = route_rule->effective_type;
12253 }
12254 }
12255 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12256 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12257 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
12258 // Deny wins if there is a conflict
12259 type_aggregate_action = route_rule->wifi_action;
12260 }
12261 }
12262 }
12263
12264 if (IFNET_IS_COMPANION_LINK(ifp) ||
12265 (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
12266 if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12267 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12268 if (interface_type_denied != NULL) {
12269 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12270 if (route_rule->effective_type != 0) {
12271 *interface_type_denied = route_rule->effective_type;
12272 }
12273 }
12274 // Mark aggregate action as deny
12275 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12276 }
12277 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
12278 if (interface_type_denied != NULL) {
12279 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12280 if (route_rule->effective_type != 0) {
12281 *interface_type_denied = route_rule->effective_type;
12282 }
12283 }
12284 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12285 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12286 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
12287 // Deny wins if there is a conflict
12288 type_aggregate_action = route_rule->companion_action;
12289 }
12290 }
12291 }
12292
12293 if (IFNET_IS_WIRED(ifp)) {
12294 if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12295 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12296 if (interface_type_denied != NULL) {
12297 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12298 if (route_rule->effective_type != 0) {
12299 *interface_type_denied = route_rule->effective_type;
12300 }
12301 }
12302 // Mark aggregate action as deny
12303 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12304 }
12305 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
12306 if (interface_type_denied != NULL) {
12307 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12308 if (route_rule->effective_type != 0) {
12309 *interface_type_denied = route_rule->effective_type;
12310 }
12311 }
12312 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12313 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12314 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
12315 // Deny wins if there is a conflict
12316 type_aggregate_action = route_rule->wired_action;
12317 }
12318 }
12319 }
12320
12321 if (IFNET_IS_EXPENSIVE(ifp)) {
12322 if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12323 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12324 // Mark aggregate action as deny
12325 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12326 }
12327 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
12328 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12329 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12330 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
12331 // Deny wins if there is a conflict
12332 type_aggregate_action = route_rule->expensive_action;
12333 }
12334 }
12335 }
12336
12337 if (IFNET_IS_CONSTRAINED(ifp)) {
12338 if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12339 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12340 // Mark aggregate action as deny
12341 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12342 }
12343 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
12344 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12345 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12346 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
12347 // Deny wins if there is a conflict
12348 type_aggregate_action = route_rule->constrained_action;
12349 }
12350 }
12351 }
12352
12353 if (IFNET_IS_VPN(ifp)) {
12354 if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12355 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12356 // Mark aggregate action as deny
12357 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12358 }
12359 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
12360 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12361 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12362 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
12363 // Deny wins if there is a conflict
12364 type_aggregate_action = route_rule->vpn_action;
12365 }
12366 }
12367 }
12368
12369 if (IFNET_IS_ULTRA_CONSTRAINED(ifp)) {
12370 if (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12371 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12372 // Mark aggregate action as deny
12373 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12374 }
12375 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->ultra_constrained_action)) {
12376 if (ultra_constrained_denied != NULL && IS_NECP_ROUTE_RULE_DENY(route_rule->ultra_constrained_action)) {
12377 *ultra_constrained_denied = true;
12378 }
12379 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12380 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12381 IS_NECP_ROUTE_RULE_DENY(route_rule->ultra_constrained_action))) {
12382 // Deny wins if there is a conflict
12383 type_aggregate_action = route_rule->ultra_constrained_action;
12384 }
12385 }
12386 }
12387
12388 if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
12389 if (necp_debug > 1) {
12390 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));
12391 }
12392 return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
12393 }
12394
12395 if (necp_debug > 1 && !default_is_allowed) {
12396 NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12397 }
12398 return default_is_allowed;
12399 }
12400
12401 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)12402 necp_proc_is_allowed_on_management_interface(proc_t proc)
12403 {
12404 bool allowed = false;
12405 const task_t __single task = proc_task(proc);
12406
12407 if (task != NULL) {
12408 if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
12409 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
12410 #if DEBUG || DEVELOPMENT
12411 || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
12412 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
12413 #endif /* DEBUG || DEVELOPMENT */
12414 ) {
12415 allowed = true;
12416 }
12417 }
12418 return allowed;
12419 }
12420
12421 __attribute__((noinline))
12422 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)12423 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12424 {
12425 char buf[128];
12426
12427 if (inp != NULL) {
12428 inp_snprintf_tuple(inp, buf, sizeof(buf));
12429 } else {
12430 *buf = 0;
12431 }
12432 os_log(OS_LOG_DEFAULT,
12433 "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
12434 proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
12435 proc != NULL ? proc_getpid(proc) : proc_selfpid(),
12436 inp != NULL ? buf : "",
12437 ifp->if_xname);
12438 }
12439
12440 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)12441 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12442 {
12443 if (if_management_interface_check_needed == false) {
12444 return true;
12445 }
12446 if (necp_drop_management_order == 0) {
12447 return true;
12448 }
12449 if (ifp == NULL && route != NULL) {
12450 ifp = route->rt_ifp;
12451 }
12452 if (ifp == NULL) {
12453 return true;
12454 }
12455
12456 if (IFNET_IS_MANAGEMENT(ifp)) {
12457 bool allowed = true;
12458
12459 if (inp != NULL) {
12460 /*
12461 * The entitlement check is already performed for socket flows
12462 */
12463 allowed = INP_MANAGEMENT_ALLOWED(inp);
12464 } else if (proc != NULL) {
12465 allowed = necp_proc_is_allowed_on_management_interface(proc);
12466 }
12467 if (__improbable(if_management_verbose > 1 && allowed == false)) {
12468 necp_log_interface_not_allowed(ifp, proc, inp);
12469 }
12470 return allowed;
12471 }
12472 return true;
12473 }
12474
12475 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,bool * ultra_constrained_denied)12476 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,
12477 u_int32_t route_rule_id, u_int32_t *interface_type_denied, bool *ultra_constrained_denied)
12478 {
12479 if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
12480 if (necp_debug > 1) {
12481 NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
12482 }
12483 return TRUE;
12484 }
12485
12486 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12487 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12488 if (aggregate_route_rule != NULL) {
12489 int index = 0;
12490 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12491 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12492 if (sub_route_rule_id == 0) {
12493 break;
12494 }
12495 if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied, ultra_constrained_denied)) {
12496 return FALSE;
12497 }
12498 }
12499 }
12500 } else {
12501 return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied, ultra_constrained_denied);
12502 }
12503
12504 return TRUE;
12505 }
12506
12507 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)12508 necp_route_rule_matches_agents(u_int32_t route_rule_id)
12509 {
12510 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12511 if (route_rule == NULL) {
12512 return false;
12513 }
12514
12515 return route_rule->match_netagent_id != 0;
12516 }
12517
12518 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)12519 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)
12520 {
12521 if (remove == NULL) {
12522 return 0;
12523 }
12524
12525 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12526 if (route_rule == NULL) {
12527 return 0;
12528 }
12529
12530 // No netagent, skip
12531 if (route_rule->netagent_id == 0) {
12532 return 0;
12533 }
12534
12535 if (route_rule->match_netagent_id != 0) {
12536 if (netagent_array == NULL || netagent_array_count == 0) {
12537 // No agents, ignore rule
12538 return 0;
12539 }
12540 bool found_match = FALSE;
12541 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12542 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12543 found_match = TRUE;
12544 break;
12545 }
12546 }
12547 if (!found_match) {
12548 // Agents don't match, ignore rule
12549 return 0;
12550 }
12551 }
12552
12553 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12554 if (ifp == NULL) {
12555 // No interface, apply the default action
12556 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12557 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12558 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12559 return route_rule->netagent_id;
12560 }
12561 return 0;
12562 }
12563
12564 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12565 if (route_rule->exception_if_indices[exception_index] == 0) {
12566 break;
12567 }
12568 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12569 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12570 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12571 route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12572 *remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12573 return route_rule->netagent_id;
12574 }
12575 return 0;
12576 }
12577 }
12578
12579 if (ifp->if_type == IFT_CELLULAR &&
12580 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12581 if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12582 route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12583 *remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12584 return route_rule->netagent_id;
12585 }
12586 return 0;
12587 }
12588
12589 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12590 route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12591 if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12592 route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12593 *remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12594 return route_rule->netagent_id;
12595 }
12596 return 0;
12597 }
12598
12599 if (IFNET_IS_COMPANION_LINK(ifp) &&
12600 route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12601 if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12602 route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12603 *remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12604 return route_rule->netagent_id;
12605 }
12606 return 0;
12607 }
12608
12609 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12610 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12611 if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12612 route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12613 *remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12614 return route_rule->netagent_id;
12615 }
12616 return 0;
12617 }
12618
12619 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12620 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12621 if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12622 route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12623 *remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12624 return route_rule->netagent_id;
12625 }
12626 return 0;
12627 }
12628
12629 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12630 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12631 if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12632 route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12633 *remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12634 return route_rule->netagent_id;
12635 }
12636 return 0;
12637 }
12638
12639 if ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12640 route_rule->ultra_constrained_action != NECP_ROUTE_RULE_NONE) {
12641 if (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12642 route_rule->ultra_constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12643 *remove = (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12644 return route_rule->netagent_id;
12645 }
12646 return 0;
12647 }
12648
12649 if (ifp->if_xflags & IFXF_IS_VPN &&
12650 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12651 if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12652 route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12653 *remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12654 return route_rule->netagent_id;
12655 }
12656 return 0;
12657 }
12658
12659 // No more specific case matched, apply the default action
12660 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12661 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12662 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12663 return route_rule->netagent_id;
12664 }
12665
12666 return 0;
12667 }
12668
12669 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)12670 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)
12671 {
12672 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12673 if (route_rule == NULL) {
12674 return 0;
12675 }
12676
12677 // No control unit, skip
12678 if (route_rule->control_unit == 0) {
12679 return 0;
12680 }
12681
12682 if (route_rule->match_netagent_id != 0) {
12683 if (netagent_array == NULL || netagent_array_count == 0) {
12684 // No agents, ignore rule
12685 return 0;
12686 }
12687 bool found_match = FALSE;
12688 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12689 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12690 found_match = TRUE;
12691 break;
12692 }
12693 }
12694 if (!found_match) {
12695 // Agents don't match, ignore rule
12696 return 0;
12697 }
12698 }
12699
12700 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12701 if (ifp == NULL) {
12702 // No interface, apply the default action
12703 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12704 return route_rule->control_unit;
12705 }
12706 return 0;
12707 }
12708
12709 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12710 if (route_rule->exception_if_indices[exception_index] == 0) {
12711 break;
12712 }
12713 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12714 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12715 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12716 return route_rule->control_unit;
12717 }
12718 return 0;
12719 }
12720 }
12721
12722 if (ifp->if_type == IFT_CELLULAR &&
12723 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12724 if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12725 return route_rule->control_unit;
12726 }
12727 return 0;
12728 }
12729
12730 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12731 route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12732 if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12733 return route_rule->control_unit;
12734 }
12735 return 0;
12736 }
12737
12738 if (IFNET_IS_COMPANION_LINK(ifp) &&
12739 route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12740 if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12741 return route_rule->control_unit;
12742 }
12743 return 0;
12744 }
12745
12746 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12747 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12748 if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12749 return route_rule->control_unit;
12750 }
12751 return 0;
12752 }
12753
12754 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12755 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12756 if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12757 return route_rule->control_unit;
12758 }
12759 return 0;
12760 }
12761
12762 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12763 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12764 if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12765 return route_rule->control_unit;
12766 }
12767 return 0;
12768 }
12769
12770 if ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12771 route_rule->ultra_constrained_action != NECP_ROUTE_RULE_NONE) {
12772 if (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12773 return route_rule->control_unit;
12774 }
12775 return 0;
12776 }
12777
12778 if (ifp->if_xflags & IFXF_IS_VPN &&
12779 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12780 if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12781 return route_rule->control_unit;
12782 }
12783 return 0;
12784 }
12785
12786 // No more specific case matched, apply the default action
12787 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12788 return route_rule->control_unit;
12789 }
12790 return 0;
12791 }
12792
12793 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)12794 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,
12795 u_int32_t *flow_divert_aggregate_unit)
12796 {
12797 if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12798 return 0;
12799 }
12800
12801 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12802 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12803 if (aggregate_route_rule != NULL) {
12804 int index = 0;
12805 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12806 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12807 if (sub_route_rule_id == 0) {
12808 break;
12809 }
12810 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12811 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12812 // For transparent proxies, accumulate the control unit and continue to the next route rule
12813 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12814 continue;
12815 }
12816
12817 if (control_unit != 0) {
12818 return control_unit;
12819 }
12820 }
12821 }
12822 } else {
12823 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12824 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12825 // For transparent proxies, accumulate the control unit and let the caller continue
12826 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12827 return 0;
12828 }
12829 return control_unit;
12830 }
12831
12832 return 0;
12833 }
12834
12835 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12836 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12837 {
12838 bool is_allowed = true;
12839 u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12840 if (route_rule_id != 0 &&
12841 interface != NULL) {
12842 lck_rw_lock_shared(&necp_kernel_policy_lock);
12843 is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL, NULL);
12844 lck_rw_done(&necp_kernel_policy_lock);
12845 }
12846 return is_allowed;
12847 }
12848
12849 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12850 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12851 {
12852 size_t netagent_cursor;
12853 for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12854 struct necp_uuid_id_mapping *mapping = NULL;
12855 u_int32_t netagent_id = netagent_ids[netagent_cursor];
12856 if (netagent_id == 0) {
12857 continue;
12858 }
12859 mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
12860 if (mapping != NULL) {
12861 u_int32_t agent_flags = 0;
12862 agent_flags = netagent_get_flags(mapping->uuid);
12863 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12864 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12865 continue;
12866 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12867 return FALSE;
12868 }
12869 }
12870 }
12871 }
12872 return TRUE;
12873 }
12874
12875 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12876 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12877 {
12878 bool allowed_to_receive = TRUE;
12879
12880 if (pf_tag == PF_TAG_ID_STACK_DROP &&
12881 (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12882 allowed_to_receive = FALSE;
12883 }
12884
12885 return allowed_to_receive;
12886 }
12887
12888 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)12889 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)
12890 {
12891 u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12892 bool allowed_to_receive = TRUE;
12893 struct necp_socket_info info = {};
12894 u_int32_t flowhash = 0;
12895 u_int32_t route_rule_id = 0;
12896 struct rtentry *route = NULL;
12897 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12898 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12899 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12900 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12901 proc_t __single socket_proc = NULL;
12902 necp_kernel_policy_filter filter_control_unit = 0;
12903 u_int32_t pass_flags = 0;
12904 u_int32_t flow_divert_aggregate_unit = 0;
12905 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12906 int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12907
12908 memset(&netagent_ids, 0, sizeof(netagent_ids));
12909
12910 if (return_policy_id) {
12911 *return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12912 }
12913 if (return_skip_policy_id) {
12914 *return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12915 }
12916 if (return_route_rule_id) {
12917 *return_route_rule_id = 0;
12918 }
12919 if (return_pass_flags) {
12920 *return_pass_flags = 0;
12921 }
12922
12923 if (inp == NULL) {
12924 goto done;
12925 }
12926
12927 route = inp->inp_route.ro_rt;
12928
12929 struct socket *so = inp->inp_socket;
12930
12931 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12932
12933 // Don't lock. Possible race condition, but we don't want the performance hit.
12934 if (necp_drop_management_order == 0 &&
12935 (necp_kernel_socket_policies_count == 0 ||
12936 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12937 if (necp_drop_all_order > 0 || drop_order > 0) {
12938 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12939 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12940 allowed_to_receive = TRUE;
12941 } else {
12942 allowed_to_receive = FALSE;
12943 }
12944 }
12945 goto done;
12946 }
12947
12948 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
12949 if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12950 bool policies_have_changed = FALSE;
12951 bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12952 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12953 policies_have_changed = TRUE;
12954 } else {
12955 if (inp->inp_policyresult.results.route_rule_id != 0) {
12956 lck_rw_lock_shared(&necp_kernel_policy_lock);
12957 if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied, NULL)) {
12958 route_allowed = FALSE;
12959 }
12960 lck_rw_done(&necp_kernel_policy_lock);
12961 }
12962 }
12963
12964 if (!policies_have_changed) {
12965 if (debug) {
12966 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);
12967 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12968 }
12969
12970 if (!route_allowed ||
12971 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12972 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12973 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12974 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12975 allowed_to_receive = FALSE;
12976 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);
12977 } else {
12978 if (return_policy_id) {
12979 *return_policy_id = inp->inp_policyresult.policy_id;
12980 }
12981 if (return_skip_policy_id) {
12982 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12983 }
12984 if (return_route_rule_id) {
12985 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12986 }
12987 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12988 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12989 }
12990 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);
12991 }
12992 goto done;
12993 }
12994 }
12995
12996 // Check for loopback exception
12997 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12998 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12999 allowed_to_receive = FALSE;
13000 goto done;
13001 }
13002 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
13003 allowed_to_receive = TRUE;
13004 goto done;
13005 }
13006
13007 // Actually calculate policy result
13008 lck_rw_lock_shared(&necp_kernel_policy_lock);
13009 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);
13010
13011 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
13012 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
13013
13014 flowhash = necp_socket_calc_flowhash_locked(&info);
13015 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13016 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
13017 inp->inp_policyresult.flowhash == flowhash) {
13018 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
13019 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13020 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13021 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
13022 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13023 (inp->inp_policyresult.results.route_rule_id != 0 &&
13024 !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied, NULL))) {
13025 allowed_to_receive = FALSE;
13026 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);
13027 } else {
13028 if (return_policy_id) {
13029 *return_policy_id = inp->inp_policyresult.policy_id;
13030 }
13031 if (return_route_rule_id) {
13032 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13033 }
13034 if (return_skip_policy_id) {
13035 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13036 }
13037 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
13038 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
13039 }
13040 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
13041 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",
13042 inp->inp_socket, info.bound_interface_index, info.protocol,
13043 inp->inp_policyresult.policy_id,
13044 inp->inp_policyresult.skip_policy_id,
13045 inp->inp_policyresult.results.result,
13046 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
13047 }
13048 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
13049 return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
13050 }
13051 lck_rw_done(&necp_kernel_policy_lock);
13052 goto done;
13053 }
13054
13055 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
13056 size_t route_rule_id_array_count = 0;
13057 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
13058 struct necp_kernel_socket_policy *matched_policy =
13059 necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
13060 &info,
13061 &filter_control_unit,
13062 route_rule_id_array,
13063 &route_rule_id_array_count,
13064 MAX_AGGREGATE_ROUTE_RULES,
13065 netagent_ids,
13066 NECP_MAX_NETAGENTS,
13067 NULL,
13068 0,
13069 NULL,
13070 0,
13071 effective_proc,
13072 pf_tag,
13073 return_skip_policy_id,
13074 inp->inp_route.ro_rt,
13075 &drop_dest_policy_result,
13076 &drop_all_bypass,
13077 &flow_divert_aggregate_unit,
13078 so,
13079 debug);
13080
13081 // Check for loopback exception again after the policy match
13082 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
13083 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
13084 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
13085 // If policies haven't changed since last evaluation, do not update filter result in order to
13086 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13087 // allow content filter to detect and drop pre-existing flows.
13088 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13089 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13090 if (info.soflow_entry != NULL) {
13091 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13092 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13093 }
13094 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13095 current_filter_control_unit != filter_control_unit) {
13096 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13097 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13098 if (info.soflow_entry != NULL) {
13099 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13100 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13101 }
13102 }
13103 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13104 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13105 }
13106 allowed_to_receive = TRUE;
13107 lck_rw_done(&necp_kernel_policy_lock);
13108
13109 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);
13110 goto done;
13111 }
13112
13113 if (info.protocol != IPPROTO_UDP) {
13114 goto skip_agent_check;
13115 }
13116
13117 // Verify netagents
13118 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
13119 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
13120 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);
13121 }
13122
13123 // Mark socket as a drop if required agent is not active
13124 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13125 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13126 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13127 inp->inp_policyresult.flowhash = flowhash;
13128 inp->inp_policyresult.results.filter_control_unit = 0;
13129 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
13130 inp->inp_policyresult.results.route_rule_id = 0;
13131 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
13132 if (info.soflow_entry != NULL) {
13133 info.soflow_entry->soflow_filter_control_unit = 0;
13134 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13135 }
13136
13137 // Unlock
13138 allowed_to_receive = FALSE;
13139 lck_rw_done(&necp_kernel_policy_lock);
13140
13141 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);
13142
13143 goto done;
13144 }
13145
13146 skip_agent_check:
13147
13148 if (route_rule_id_array_count == 1) {
13149 route_rule_id = route_rule_id_array[0];
13150 } else if (route_rule_id_array_count > 1) {
13151 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
13152 }
13153
13154 bool send_local_network_denied_event = false;
13155 if (matched_policy != NULL) {
13156 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
13157 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
13158 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
13159 // Trigger the event that we dropped due to a local network policy
13160 send_local_network_denied_event = true;
13161 }
13162
13163 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
13164 matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13165 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13166 matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
13167 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13168 (route_rule_id != 0 &&
13169 !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied, NULL)) ||
13170 !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
13171 allowed_to_receive = FALSE;
13172 } else {
13173 if (return_policy_id) {
13174 *return_policy_id = matched_policy->id;
13175 }
13176 if (return_route_rule_id) {
13177 *return_route_rule_id = route_rule_id;
13178 }
13179 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
13180 pass_flags = matched_policy->result_parameter.pass_flags;
13181 }
13182 // If policies haven't changed since last evaluation, do not update filter result in order to
13183 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13184 // allow content filter to detect and drop pre-existing flows.
13185 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13186 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13187 if (info.soflow_entry != NULL) {
13188 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13189 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13190 }
13191 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13192 current_filter_control_unit != filter_control_unit) {
13193 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13194 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13195 if (info.soflow_entry != NULL) {
13196 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13197 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13198 }
13199 }
13200 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13201 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13202 }
13203 }
13204
13205 if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
13206 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>",
13207 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);
13208 }
13209 } else {
13210 bool drop_all = false;
13211 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
13212 drop_all = true;
13213 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
13214 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
13215 }
13216 }
13217 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
13218 allowed_to_receive = FALSE;
13219 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
13220 } else {
13221 if (return_policy_id) {
13222 *return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13223 }
13224 if (return_route_rule_id) {
13225 *return_route_rule_id = route_rule_id;
13226 }
13227
13228 // If policies haven't changed since last evaluation, do not update filter result in order to
13229 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13230 // allow content filter to detect and drop pre-existing flows.
13231 uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13232 int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13233 if (info.soflow_entry != NULL) {
13234 current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13235 current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13236 }
13237 if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13238 current_filter_control_unit != filter_control_unit) {
13239 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13240 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13241 if (info.soflow_entry != NULL) {
13242 info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13243 info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13244 }
13245 }
13246 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13247 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13248 }
13249 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);
13250 }
13251 }
13252
13253 if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
13254 allowed_to_receive = FALSE;
13255 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
13256 }
13257
13258 lck_rw_done(&necp_kernel_policy_lock);
13259
13260 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
13261 inp->inp_policyresult.network_denied_notifies++;
13262 #if defined(XNU_TARGET_OS_OSX)
13263 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
13264 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13265 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13266 NETPOLICY_NETWORKTYPE_LOCAL);
13267 #else
13268 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13269 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13270 NETPOLICY_NETWORKTYPE_LOCAL);
13271 #endif
13272 }
13273
13274 done:
13275 if (return_pass_flags != NULL) {
13276 *return_pass_flags = pass_flags;
13277 }
13278
13279 if (pf_tag != 0 && allowed_to_receive) {
13280 allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
13281 }
13282
13283 if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
13284 soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
13285 }
13286
13287 if (socket_proc) {
13288 proc_rele(socket_proc);
13289 }
13290
13291 if (info.soflow_entry != NULL) {
13292 soflow_free_flow(info.soflow_entry);
13293 }
13294
13295 return allowed_to_receive;
13296 }
13297
13298 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)13299 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)
13300 {
13301 struct sockaddr_in local = {};
13302 struct sockaddr_in remote = {};
13303 local.sin_family = remote.sin_family = AF_INET;
13304 local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
13305 local.sin_port = local_port;
13306 remote.sin_port = remote_port;
13307 memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
13308 memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
13309
13310 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13311 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13312 }
13313
13314 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)13315 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)
13316 {
13317 struct sockaddr_in6 local = {};
13318 struct sockaddr_in6 remote = {};
13319 local.sin6_family = remote.sin6_family = AF_INET6;
13320 local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
13321 local.sin6_port = local_port;
13322 remote.sin6_port = remote_port;
13323 memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
13324 memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
13325
13326 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13327 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13328 }
13329
13330 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)13331 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,
13332 u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13333 {
13334 return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
13335 return_policy_id, return_route_rule_id,
13336 return_skip_policy_id, return_pass_flags);
13337 }
13338
13339 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)13340 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
13341 necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
13342 {
13343 if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
13344 return EINVAL;
13345 }
13346
13347 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13348 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
13349 policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
13350 }
13351
13352 // Mark ID for Pass and IP Tunnel
13353 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13354 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13355 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
13356 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
13357 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13358 } else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
13359 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
13360 // This case is same as a PASS
13361 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13362 } else {
13363 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13364 }
13365 packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
13366 if (route_rule_id != 0) {
13367 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
13368 } else {
13369 packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13370 }
13371 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);
13372
13373 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13374 skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13375 // Only mark the skip policy if it is a valid policy ID
13376 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13377 } else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13378 inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13379 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13380 } else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
13381 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
13382 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
13383 // See necp_get_skip_policy_id_from_packet() and
13384 // necp_packet_should_skip_filters().
13385 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13386 } else {
13387 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13388 }
13389
13390 if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
13391 ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
13392 m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
13393 }
13394
13395 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13396 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
13397 packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
13398 }
13399
13400 return 0;
13401 }
13402
13403 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)13404 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
13405 {
13406 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13407 return EINVAL;
13408 }
13409
13410 // Mark ID for Pass and IP Tunnel
13411 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13412 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13413 } else {
13414 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13415 }
13416
13417 return 0;
13418 }
13419
13420 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)13421 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
13422 {
13423 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13424 return EINVAL;
13425 }
13426
13427 // Mark ID for Pass and IP Tunnel
13428 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13429 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13430 } else {
13431 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13432 }
13433
13434 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13435 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13436 } else {
13437 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13438 }
13439 return 0;
13440 }
13441
13442 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)13443 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
13444 {
13445 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13446 return EINVAL;
13447 }
13448
13449 // Mark ID for Pass and IP Tunnel
13450 if (interface != NULL) {
13451 packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
13452 }
13453
13454 return 0;
13455 }
13456
13457 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)13458 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
13459 {
13460 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13461 return EINVAL;
13462 }
13463
13464 if (is_keepalive) {
13465 packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
13466 } else {
13467 packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
13468 }
13469
13470 return 0;
13471 }
13472
13473 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)13474 necp_get_policy_id_from_packet(struct mbuf *packet)
13475 {
13476 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13477 return NECP_KERNEL_POLICY_ID_NONE;
13478 }
13479
13480 return packet->m_pkthdr.necp_mtag.necp_policy_id;
13481 }
13482
13483 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)13484 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
13485 {
13486 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13487 return NECP_KERNEL_POLICY_ID_NONE;
13488 }
13489
13490 // Check for overloaded value. See necp_mark_packet_from_socket().
13491 if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
13492 return NECP_KERNEL_POLICY_ID_NONE;
13493 }
13494
13495 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
13496 }
13497
13498 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)13499 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
13500 {
13501 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13502 return 0;
13503 }
13504
13505 return m_pftag(packet)->pftag_tag;
13506 }
13507
13508 bool
necp_packet_should_skip_filters(struct mbuf * packet)13509 necp_packet_should_skip_filters(struct mbuf *packet)
13510 {
13511 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13512 return false;
13513 }
13514
13515 // Check for overloaded value. See necp_mark_packet_from_socket().
13516 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
13517 }
13518
13519 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)13520 necp_get_last_interface_index_from_packet(struct mbuf *packet)
13521 {
13522 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13523 return 0;
13524 }
13525
13526 return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
13527 }
13528
13529 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)13530 necp_get_route_rule_id_from_packet(struct mbuf *packet)
13531 {
13532 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13533 return 0;
13534 }
13535
13536 return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
13537 }
13538
13539 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)13540 necp_get_app_uuid_from_packet(struct mbuf *packet,
13541 uuid_t app_uuid)
13542 {
13543 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13544 return EINVAL;
13545 }
13546
13547 bool found_mapping = FALSE;
13548 if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
13549 lck_rw_lock_shared(&necp_kernel_policy_lock);
13550 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);
13551 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
13552 if (entry != NULL) {
13553 uuid_copy(app_uuid, entry->uuid);
13554 found_mapping = true;
13555 }
13556 lck_rw_done(&necp_kernel_policy_lock);
13557 }
13558 if (!found_mapping) {
13559 uuid_clear(app_uuid);
13560 }
13561 return 0;
13562 }
13563
13564 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)13565 necp_get_is_keepalive_from_packet(struct mbuf *packet)
13566 {
13567 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13568 return FALSE;
13569 }
13570
13571 return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
13572 }
13573
13574 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)13575 necp_socket_get_content_filter_control_unit(struct socket *so)
13576 {
13577 struct inpcb *inp = sotoinpcb(so);
13578
13579 if (inp == NULL) {
13580 return 0;
13581 }
13582 return inp->inp_policyresult.results.filter_control_unit;
13583 }
13584
13585 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)13586 necp_socket_get_policy_gencount(struct socket *so)
13587 {
13588 struct inpcb *inp = so ? sotoinpcb(so) : NULL;
13589
13590 if (inp == NULL) {
13591 return 0;
13592 }
13593 return inp->inp_policyresult.policy_gencount;
13594 }
13595
13596 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)13597 necp_socket_should_use_flow_divert(struct inpcb *inp)
13598 {
13599 if (inp == NULL) {
13600 return FALSE;
13601 }
13602
13603 return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
13604 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13605 (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
13606 }
13607
13608 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)13609 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
13610 {
13611 if (inp == NULL) {
13612 return 0;
13613 }
13614
13615 if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13616 return 0;
13617 }
13618
13619 if (aggregate_unit != NULL &&
13620 inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13621 *aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13622 }
13623
13624 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13625 return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13626 }
13627
13628 return 0;
13629 }
13630
13631 bool
necp_socket_should_rescope(struct inpcb * inp)13632 necp_socket_should_rescope(struct inpcb *inp)
13633 {
13634 if (inp == NULL) {
13635 return FALSE;
13636 }
13637
13638 return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13639 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13640 }
13641
13642 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13643 necp_socket_get_rescope_if_index(struct inpcb *inp)
13644 {
13645 if (inp == NULL) {
13646 return 0;
13647 }
13648
13649 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13650 return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13651 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13652 return necp_get_primary_direct_interface_index();
13653 }
13654
13655 return 0;
13656 }
13657
13658 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13659 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13660 {
13661 if (inp == NULL) {
13662 return current_mtu;
13663 }
13664
13665 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13666 (inp->inp_flags & INP_BOUND_IF) &&
13667 inp->inp_boundifp) {
13668 u_int bound_interface_index = inp->inp_boundifp->if_index;
13669 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13670
13671 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13672 if (bound_interface_index != tunnel_interface_index) {
13673 ifnet_t tunnel_interface = NULL;
13674
13675 ifnet_head_lock_shared();
13676 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13677 ifnet_head_done();
13678
13679 if (tunnel_interface != NULL) {
13680 u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13681 u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13682 const char ipsec_prefix[] = "ipsec";
13683 if (delegate_tunnel_mtu != 0 &&
13684 strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13685 // For ipsec interfaces, calculate the overhead from the delegate interface
13686 u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13687 if (delegate_tunnel_mtu > tunnel_overhead) {
13688 delegate_tunnel_mtu -= tunnel_overhead;
13689 }
13690
13691 if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13692 // If the (delegate - overhead) < direct, return (delegate - overhead)
13693 return delegate_tunnel_mtu;
13694 } else {
13695 // Otherwise return direct
13696 return direct_tunnel_mtu;
13697 }
13698 } else {
13699 // For non-ipsec interfaces, just return the tunnel MTU
13700 return direct_tunnel_mtu;
13701 }
13702 }
13703 }
13704 }
13705
13706 // By default, just return the MTU passed in
13707 return current_mtu;
13708 }
13709
13710 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13711 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13712 {
13713 if (result_parameter == NULL) {
13714 return NULL;
13715 }
13716
13717 return ifindex2ifnet[result_parameter->tunnel_interface_index];
13718 }
13719
13720 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13721 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13722 {
13723 bool found_match = FALSE;
13724 bool can_rebind = FALSE;
13725 ifaddr_t ifa;
13726 union necp_sockaddr_union address_storage;
13727
13728 if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13729 return FALSE;
13730 }
13731
13732 // Match source address against interface addresses
13733 ifnet_lock_shared(interface);
13734 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13735 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13736 if (address_storage.sa.sa_family != family) {
13737 continue;
13738 }
13739
13740 if (family == AF_INET) {
13741 struct ip *ip = mtod(packet, struct ip *);
13742 if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13743 found_match = TRUE;
13744 break;
13745 }
13746 } else if (family == AF_INET6) {
13747 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13748 if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13749 found_match = TRUE;
13750 break;
13751 }
13752 }
13753 }
13754 }
13755 const uint32_t if_idx = interface->if_index;
13756 ifnet_lock_done(interface);
13757
13758 // If source address matched, attempt to construct a route to the destination address
13759 if (found_match) {
13760 ROUTE_RELEASE(new_route);
13761
13762 if (family == AF_INET) {
13763 struct ip *ip = mtod(packet, struct ip *);
13764 struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13765 dst4->sin_family = AF_INET;
13766 dst4->sin_len = sizeof(struct sockaddr_in);
13767 dst4->sin_addr = ip->ip_dst;
13768 rtalloc_scoped(new_route, if_idx);
13769 if (!ROUTE_UNUSABLE(new_route)) {
13770 can_rebind = TRUE;
13771 }
13772 } else if (family == AF_INET6) {
13773 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13774 struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13775 dst6->sin6_family = AF_INET6;
13776 dst6->sin6_len = sizeof(struct sockaddr_in6);
13777 dst6->sin6_addr = ip6->ip6_dst;
13778 rtalloc_scoped(new_route, if_idx);
13779 if (!ROUTE_UNUSABLE(new_route)) {
13780 can_rebind = TRUE;
13781 }
13782 }
13783 }
13784
13785 return can_rebind;
13786 }
13787
13788 static bool
necp_addr_is_loopback(struct sockaddr * address)13789 necp_addr_is_loopback(struct sockaddr *address)
13790 {
13791 if (address == NULL) {
13792 return FALSE;
13793 }
13794
13795 if (address->sa_family == AF_INET) {
13796 return IN_LOOPBACK(ntohl(SIN(address)->sin_addr.s_addr));
13797 } else if (address->sa_family == AF_INET6) {
13798 if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13799 return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13800 } else {
13801 // Match ::ffff:127.0.0.1 loopback address
13802 in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13803 return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13804 }
13805 }
13806
13807 return FALSE;
13808 }
13809
13810 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)13811 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13812 {
13813 // Note: This function only checks for the loopback addresses.
13814 // In the future, we may want to expand to also allow any traffic
13815 // going through the loopback interface, but until then, this
13816 // check is cheaper.
13817
13818 if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13819 return TRUE;
13820 }
13821
13822 if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13823 return TRUE;
13824 }
13825
13826 if (inp != NULL) {
13827 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13828 return TRUE;
13829 }
13830 if (inp->inp_vflag & INP_IPV4) {
13831 if (IN_LOOPBACK(ntohl(inp->inp_laddr.s_addr)) ||
13832 IN_LOOPBACK(ntohl(inp->inp_faddr.s_addr))) {
13833 return TRUE;
13834 }
13835 } else if (inp->inp_vflag & INP_IPV6) {
13836 if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13837 IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13838 return TRUE;
13839 }
13840 }
13841 } else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13842 return TRUE;
13843 }
13844
13845 if (packet != NULL) {
13846 struct ip *ip = mtod(packet, struct ip *);
13847 if (ip->ip_v == 4) {
13848 if (IN_LOOPBACK(ntohl(ip->ip_src.s_addr))) {
13849 return TRUE;
13850 }
13851 if (IN_LOOPBACK(ntohl(ip->ip_dst.s_addr))) {
13852 return TRUE;
13853 }
13854 } else if (ip->ip_v == 6) {
13855 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13856 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13857 return TRUE;
13858 }
13859 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13860 return TRUE;
13861 }
13862 }
13863 }
13864
13865 return FALSE;
13866 }
13867
13868 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13869 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13870 {
13871 if (inp != NULL) {
13872 if (!(inp->inp_vflag & INP_IPV6)) {
13873 return false;
13874 }
13875 if (INP_INTCOPROC_ALLOWED(inp)) {
13876 return true;
13877 }
13878 if ((inp->inp_flags & INP_BOUND_IF) &&
13879 IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13880 return true;
13881 }
13882 return false;
13883 }
13884 if (packet != NULL) {
13885 struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13886 struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13887 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13888 NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13889 return true;
13890 }
13891 }
13892
13893 return false;
13894 }
13895
13896 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13897 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13898 {
13899 char dest_str[MAX_IPv6_STR_LEN];
13900
13901 if (necp_drop_dest_debug > 0) {
13902 if (sau->sa.sa_family == AF_INET) {
13903 (void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13904 } else if (sau->sa.sa_family == AF_INET6) {
13905 (void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13906 } else {
13907 dest_str[0] = 0;
13908 }
13909 }
13910 for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13911 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13912 struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13913
13914 if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13915 if (necp_drop_dest_debug > 0) {
13916 char subnet_str[MAX_IPv6_STR_LEN];
13917 struct proc *p = current_proc();
13918 pid_t pid = proc_pid(p);
13919
13920 if (sau->sa.sa_family == AF_INET) {
13921 (void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13922 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);
13923 } else if (sau->sa.sa_family == AF_INET6) {
13924 (void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13925 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);
13926 }
13927 }
13928 return true;
13929 }
13930 }
13931 if (necp_drop_dest_debug > 1) {
13932 struct proc *p = current_proc();
13933 pid_t pid = proc_pid(p);
13934
13935 os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13936 }
13937 return false;
13938 }
13939
13940 static int
13941 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13942 {
13943 #pragma unused(arg1, arg2, oidp)
13944 int changed = 0;
13945 int error = 0;
13946 struct necp_drop_dest_policy tmp_drop_dest_policy;
13947 struct proc *p = current_proc();
13948 pid_t pid = proc_pid(p);
13949
13950 if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13951 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13952 NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13953 return EPERM;
13954 }
13955 if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13956 NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13957 return EINVAL;
13958 }
13959
13960 memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13961 error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13962 if (error != 0) {
13963 NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13964 return error;
13965 }
13966 if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13967 return error;
13968 }
13969
13970 //
13971 // Validate the passed parameters
13972 //
13973 if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13974 NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13975 return EINVAL;
13976 }
13977 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13978 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13979 struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13980
13981 switch (tmp_drop_dest_entry->level) {
13982 case NECP_SESSION_PRIORITY_UNKNOWN:
13983 if (tmp_drop_dest_policy.entry_count != 0) {
13984 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);
13985 return EINVAL;
13986 }
13987 break;
13988 case NECP_SESSION_PRIORITY_CONTROL:
13989 case NECP_SESSION_PRIORITY_CONTROL_1:
13990 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13991 case NECP_SESSION_PRIORITY_HIGH:
13992 case NECP_SESSION_PRIORITY_HIGH_1:
13993 case NECP_SESSION_PRIORITY_HIGH_2:
13994 case NECP_SESSION_PRIORITY_HIGH_3:
13995 case NECP_SESSION_PRIORITY_HIGH_4:
13996 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13997 case NECP_SESSION_PRIORITY_DEFAULT:
13998 case NECP_SESSION_PRIORITY_LOW:
13999 if (tmp_drop_dest_policy.entry_count == 0) {
14000 NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
14001 return EINVAL;
14002 }
14003 break;
14004 default: {
14005 NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
14006 return EINVAL;
14007 }
14008 }
14009
14010 switch (npca->address.sa.sa_family) {
14011 case AF_INET: {
14012 if (npca->prefix > 32) {
14013 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
14014 return EINVAL;
14015 }
14016 if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
14017 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
14018 return EINVAL;
14019 }
14020 if (npca->address.sin.sin_port != 0) {
14021 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);
14022 return EINVAL;
14023 }
14024 break;
14025 }
14026 case AF_INET6: {
14027 if (npca->prefix > 128) {
14028 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
14029 return EINVAL;
14030 }
14031 if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
14032 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
14033 return EINVAL;
14034 }
14035 if (npca->address.sin6.sin6_port != 0) {
14036 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);
14037 return EINVAL;
14038 }
14039 if (npca->address.sin6.sin6_flowinfo != 0) {
14040 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);
14041 return EINVAL;
14042 }
14043 if (npca->address.sin6.sin6_scope_id != 0) {
14044 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);
14045 return EINVAL;
14046 }
14047 break;
14048 }
14049 default: {
14050 return EINVAL;
14051 }
14052 }
14053 }
14054
14055 //
14056 // Commit the changed policy
14057 //
14058 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
14059 memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
14060
14061 necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
14062 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
14063 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
14064 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
14065
14066 memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
14067
14068 necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
14069 }
14070 lck_rw_done(&necp_kernel_policy_lock);
14071
14072 return 0;
14073 }
14074
14075 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])14076 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
14077 {
14078 uint16_t fam = address->sa.sa_family;
14079 memset(addr_str, 0, MAX_IPv6_STR_LEN);
14080 if (fam == AF_INET) {
14081 (void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
14082 } else if (fam == AF_INET6) {
14083 (void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
14084 }
14085 return __unsafe_null_terminated_from_indexable(addr_str);
14086 }
14087