1 /*
2 * Copyright (c) 2013-2024 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <string.h>
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/malloc.h>
34 #include <sys/kernel.h>
35 #include <sys/kern_control.h>
36 #include <sys/mbuf.h>
37 #include <sys/kpi_mbuf.h>
38 #include <sys/proc_uuid_policy.h>
39 #include <net/if.h>
40 #include <sys/domain.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/coalition.h>
45 #include <sys/ubc.h>
46 #include <sys/codesign.h>
47 #include <kern/cs_blobs.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip6.h>
50 #include <netinet/tcp.h>
51 #include <netinet/tcp_var.h>
52 #include <netinet/tcp_cache.h>
53 #include <netinet/udp.h>
54 #include <netinet/in_pcb.h>
55 #include <netinet/in_tclass.h>
56 #include <netinet6/esp.h>
57 #include <net/flowhash.h>
58 #include <net/bloom_filter.h>
59 #include <net/if_var.h>
60 #include <net/pfvar.h>
61 #if SKYWALK
62 #include <skywalk/lib/net_filter_event.h>
63 #endif /* defined(SKYWALK) */
64 #include <sys/kauth.h>
65 #include <sys/sysctl.h>
66 #include <sys/sysproto.h>
67 #include <sys/priv.h>
68 #include <sys/kern_event.h>
69 #include <sys/file_internal.h>
70 #include <IOKit/IOBSD.h>
71 #include <libkern/crypto/rand.h>
72 #include <corecrypto/cchmac.h>
73 #include <corecrypto/ccsha2.h>
74 #include <os/refcnt.h>
75 #include <mach-o/loader.h>
76 #include <net/network_agent.h>
77 #include <net/necp.h>
78 #include <netinet/flow_divert_proto.h>
79 #include <kern/socket_flows.h>
80
81 #include <net/sockaddr_utils.h>
82 #include <net/trie_utility.h>
83
84 /*
85 * NECP - Network Extension Control Policy database
86 * ------------------------------------------------
87 * The goal of this module is to allow clients connecting via a
88 * policy file descriptor to create high-level policy sessions, which
89 * are ingested into low-level kernel policies that control and tag
90 * traffic at the application, socket, and IP layers.
91 *
92 * ------------------------------------------------
93 * Sessions
94 * ------------------------------------------------
95 * Each session owns a list of session policies, each of which can
96 * specify any combination of conditions and a single result. Each
97 * session also has a priority level (such as High, Default, or Low)
98 * which is requested by the client. Based on the requested level,
99 * a session order value is assigned to the session, which will be used
100 * to sort kernel policies generated by the session. The session client
101 * can specify the sub-order for each policy it creates which will be
102 * used to further sort the kernel policies.
103 *
104 * Policy fd --> 1 necp_session --> list of necp_session_policy structs
105 *
106 * ------------------------------------------------
107 * Kernel Policies
108 * ------------------------------------------------
109 * Whenever a session send the Apply command, its policies are ingested
110 * and generate kernel policies. There are two phases of kernel policy
111 * ingestion.
112 *
113 * 1. The session policy is parsed to create kernel policies at the socket
114 * and IP layers, when applicable. For example, a policy that requires
115 * all traffic from App1 to Pass will generate a socket kernel policy to
116 * match App1 and mark packets with ID1, and also an IP policy to match
117 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
118 * resulting kernel policies are added to the global socket and IP layer
119 * policy lists.
120 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
121 * || ||
122 * \/ \/
123 * necp_kernel_socket_policies necp_kernel_ip_output_policies
124 *
125 * 2. Once the global lists of kernel policies have been filled out, each
126 * list is traversed to create optimized sub-lists ("Maps") which are used during
127 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
128 * which hashes incoming packets based on marked socket-layer policies, and removes
129 * duplicate or overlapping policies. Socket policies are sent into two maps,
130 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
131 * The app layer map is used for policy checks coming in from user space, and is one
132 * list with duplicate and overlapping policies removed. The socket map hashes based
133 * on app UUID, and removes duplicate and overlapping policies.
134 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
135 * |-> necp_kernel_socket_policies_map
136 *
137 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
138 *
139 * ------------------------------------------------
140 * Drop All Level
141 * ------------------------------------------------
142 * The Drop All Level is a sysctl that controls the level at which policies are allowed
143 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
144 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
145 * by a session with a priority level better than (numerically less than) the
146 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
147 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
148 * session orders to be dropped.
149 */
150
151 u_int32_t necp_drop_all_order = 0;
152 u_int32_t necp_drop_all_level = 0;
153
154 u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
155 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
156 u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
157 u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
158 u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
159
160 u_int32_t necp_drop_unentitled_order = 0;
161 #ifdef XNU_TARGET_OS_WATCH
162 u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
163 #else // XNU_TARGET_OS_WATCH
164 u_int32_t necp_drop_unentitled_level = 0;
165 #endif // XNU_TARGET_OS_WATCH
166
167 u_int32_t necp_drop_management_order = 0;
168 u_int32_t necp_drop_management_level = NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL;
169
170 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
171
172 os_log_t necp_log_handle = NULL;
173 os_log_t necp_data_trace_log_handle = NULL;
174
175 u_int32_t necp_session_count = 0;
176 u_int32_t necp_trie_count = 0;
177
178 static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
179 struct necp_session_policy, NET_KT_DEFAULT);
180 static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
181 struct necp_kernel_socket_policy, NET_KT_DEFAULT);
182 static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
183 struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
184
185 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
186 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
187 LIST_INSERT_HEAD((head), elm, field); \
188 } else { \
189 LIST_FOREACH(tmpelm, head, field) { \
190 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
191 LIST_INSERT_AFTER(tmpelm, elm, field); \
192 break; \
193 } \
194 } \
195 } \
196 } while (0)
197
198 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
199 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
200 LIST_INSERT_HEAD((head), elm, field); \
201 } else { \
202 LIST_FOREACH(tmpelm, head, field) { \
203 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield))) { \
204 LIST_INSERT_AFTER(tmpelm, elm, field); \
205 break; \
206 } \
207 } \
208 } \
209 } while (0)
210
211 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
212 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield == (elm)->secondsortfield) && (LIST_FIRST(head)->thirdsortfield >= (elm)->thirdsortfield))) { \
213 LIST_INSERT_HEAD((head), elm, field); \
214 } else { \
215 LIST_FOREACH(tmpelm, head, field) { \
216 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield == (elm)->secondsortfield) && (LIST_NEXT(tmpelm, field)->thirdsortfield >= (elm)->thirdsortfield))) { \
217 LIST_INSERT_AFTER(tmpelm, elm, field); \
218 break; \
219 } \
220 } \
221 } \
222 } while (0)
223
224 #define IS_NECP_ROUTE_RULE_DENY(x) ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE)
225
226 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x) (IS_NECP_ROUTE_RULE_DENY(x) || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
227
228 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x000001
229 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x000002
230 #define NECP_KERNEL_CONDITION_PROTOCOL 0x000004
231 #define NECP_KERNEL_CONDITION_LOCAL_START 0x000008
232 #define NECP_KERNEL_CONDITION_LOCAL_END 0x000010
233 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x000020
234 #define NECP_KERNEL_CONDITION_REMOTE_START 0x000040
235 #define NECP_KERNEL_CONDITION_REMOTE_END 0x000080
236 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x000100
237 #define NECP_KERNEL_CONDITION_APP_ID 0x000200
238 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x000400
239 #define NECP_KERNEL_CONDITION_DOMAIN 0x000800
240 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x001000
241 #define NECP_KERNEL_CONDITION_POLICY_ID 0x002000
242 #define NECP_KERNEL_CONDITION_PID 0x004000
243 #define NECP_KERNEL_CONDITION_UID 0x008000
244 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x010000 // Only set from packets looping between interfaces
245 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x020000
246 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x040000
247 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 0x080000
248 #define NECP_KERNEL_CONDITION_AGENT_TYPE 0x100000
249 #define NECP_KERNEL_CONDITION_HAS_CLIENT 0x200000
250 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS 0x400000
251 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS 0x800000
252 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY 0x1000000
253 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY 0x2000000
254 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY 0x4000000
255 #define NECP_KERNEL_CONDITION_SDK_VERSION 0x8000000
256 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x10000000
257 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 0x20000000
258 #define NECP_KERNEL_CONDITION_IS_LOOPBACK 0x40000000
259 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY 0x80000000
260 #define NECP_KERNEL_CONDITION_SCHEME_PORT 0x100000000
261 #define NECP_KERNEL_CONDITION_DOMAIN_FILTER 0x200000000
262 #define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT 0x400000000
263 #define NECP_KERNEL_CONDITION_EXACT_DOMAIN 0x800000000
264 #define NECP_KERNEL_CONDITION_REAL_UID 0x1000000000
265 #define NECP_KERNEL_CONDITION_URL 0x2000000000
266 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS 0x4000000000
267
268 #define NECP_MAX_POLICY_RESULT_SIZE 512
269 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
270 #define NECP_MAX_CONDITIONS_ARRAY_SIZE 4096
271 #define NECP_MAX_POLICY_LIST_COUNT 1024
272
273 #define NECP_MAX_DOMAIN_FILTER_SIZE 65536 // Allows room for 100K domains
274 #define NECP_MAX_DOMAIN_TRIE_SIZE (1024 * 512) // Allows 5000+ domains
275
276 typedef enum {
277 NECP_BYPASS_TYPE_NONE = 0,
278 NECP_BYPASS_TYPE_INTCOPROC = 1,
279 NECP_BYPASS_TYPE_LOOPBACK = 2,
280 NECP_BYPASS_TYPE_DROP = 3, // Drop now without hitting necp policies
281 } necp_socket_bypass_type_t;
282
283 // Cap the policy size at the max result + conditions size, with room for extra TLVs
284 #define NECP_MAX_POLICY_SIZE (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
285
286 struct necp_service_registration {
287 LIST_ENTRY(necp_service_registration) session_chain;
288 LIST_ENTRY(necp_service_registration) kernel_chain;
289 u_int32_t service_id;
290 };
291
292 struct necp_domain_filter {
293 LIST_ENTRY(necp_domain_filter) owner_chain;
294 LIST_ENTRY(necp_domain_filter) chain;
295 u_int32_t id;
296 struct net_bloom_filter *filter;
297 os_refcnt_t refcount;
298 };
299 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
300
301 /*
302 * Filter id space is split between domain bloom filter id and domain trie filter id.
303 * id <= 10000 - bloom filter ids
304 * id > 10000 - trie filter ids
305 */
306 #define NECP_DOMAIN_FILTER_ID_MAX 10000
307 #define NECP_DOMAIN_TRIE_ID_START NECP_DOMAIN_FILTER_ID_MAX
308 #define NECP_IS_DOMAIN_FILTER_ID(id) (id <= NECP_DOMAIN_FILTER_ID_MAX)
309
310 struct necp_domain_trie {
311 LIST_ENTRY(necp_domain_trie) owner_chain;
312 LIST_ENTRY(necp_domain_trie) chain;
313 u_int32_t id;
314 struct necp_domain_trie_request *trie_request;
315 size_t trie_request_size;
316 struct net_trie trie;
317 os_refcnt_t refcount;
318 };
319 static LIST_HEAD(necp_domain_trie_list, necp_domain_trie) necp_global_domain_trie_list;
320
321 struct necp_session {
322 u_int8_t necp_fd_type;
323 u_int32_t control_unit;
324 u_int32_t session_priority; // Descriptive priority rating
325 u_int32_t session_order;
326
327 necp_policy_id last_policy_id;
328
329 decl_lck_mtx_data(, lock);
330
331 bool proc_locked; // Messages must come from proc_uuid
332 uuid_t proc_uuid;
333 int proc_pid;
334
335 bool dirty;
336 LIST_HEAD(_policies, necp_session_policy) policies;
337
338 LIST_HEAD(_services, necp_service_registration) services;
339 struct necp_domain_filter_list domain_filters;
340 struct necp_domain_trie_list domain_tries;
341
342 TAILQ_ENTRY(necp_session) chain;
343 };
344
345 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
346 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
347
348 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
349
350 struct necp_socket_info {
351 pid_t pid;
352 int32_t pid_version;
353 uid_t uid;
354 uid_t real_uid;
355 union necp_sockaddr_union local_addr;
356 union necp_sockaddr_union remote_addr;
357 u_int32_t bound_interface_index;
358 u_int32_t bound_interface_flags;
359 u_int32_t bound_interface_eflags;
360 u_int32_t bound_interface_xflags;
361 u_int32_t traffic_class;
362 u_int16_t protocol;
363 u_int16_t scheme_port;
364 u_int32_t application_id;
365 u_int32_t real_application_id;
366 u_int32_t account_id;
367 u_int32_t drop_order;
368 u_int32_t client_flags;
369 char *domain __null_terminated;
370 char *url __null_terminated;
371 unsigned is_entitled : 1;
372 unsigned has_client : 1;
373 unsigned has_system_signed_result : 1;
374 unsigned is_platform_binary : 1;
375 unsigned used_responsible_pid : 1;
376 unsigned is_loopback : 1;
377 unsigned real_is_platform_binary : 1;
378 unsigned is_delegated : 1;
379 unsigned is_local : 1;
380 unsigned __pad_bits : 7;
381 };
382
383 static LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
384 static LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
385 static LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
386 &necp_kernel_policy_mtx_attr);
387
388 static LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
389 static LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
390
391 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
392
393 /*
394 * On modification, invalidate cached lookups by bumping the generation count.
395 * Other calls will need to take the slowpath of taking
396 * the subsystem lock.
397 */
398 static volatile int32_t necp_kernel_socket_policies_gencount;
399 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
400 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
401 necp_kernel_socket_policies_gencount = 1; \
402 } \
403 } while (0)
404
405 /*
406 * Drop-all Bypass:
407 * Allow priviledged processes to bypass the default drop-all
408 * via entitlement check. For OSX, since entitlement check is
409 * not supported for configd, configd signing identity is checked
410 * instead.
411 */
412 #define SIGNING_ID_CONFIGD "com.apple.configd"
413 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
414
415 typedef enum {
416 NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
417 NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
418 NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
419 } necp_drop_all_bypass_check_result_t;
420
421 static u_int64_t necp_kernel_application_policies_condition_mask;
422 static size_t necp_kernel_application_policies_count;
423 static u_int64_t necp_kernel_socket_policies_condition_mask;
424 static size_t necp_kernel_socket_policies_count;
425 static size_t necp_kernel_socket_policies_non_app_count;
426 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
427 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
428 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
429 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
430 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
431 static size_t necp_kernel_socket_policies_app_layer_map_count;
432 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_app_layer_map;
433 /*
434 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
435 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
436 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
437 *
438 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
439 */
440
441 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
442 static size_t necp_kernel_ip_output_policies_count;
443 static size_t necp_kernel_ip_output_policies_non_id_count;
444 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
445 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
446 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
447 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
448 static struct necp_kernel_ip_output_policy ** __indexable necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
449 static struct necp_kernel_socket_policy pass_policy =
450 {
451 .id = NECP_KERNEL_POLICY_ID_NO_MATCH,
452 .result = NECP_KERNEL_POLICY_RESULT_PASS,
453 };
454
455 static struct necp_session *necp_create_session(void);
456 static void necp_delete_session(struct necp_session *session);
457
458 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
459 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
460 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
461
462 #define MAX_RESULT_STRING_LEN 64
463 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);
464
465 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);
466 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
467 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
468 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
469 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
470 static void necp_policy_apply_all(struct necp_session *session);
471
472 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);
473 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
474 static bool necp_kernel_socket_policies_reprocess(void);
475 static bool necp_kernel_socket_policies_update_uuid_table(void);
476 static inline struct necp_kernel_socket_policy * necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
477 struct necp_socket_info *info,
478 necp_kernel_policy_filter *return_filter,
479 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
480 size_t *return_route_rule_id_array_count,
481 size_t route_rule_id_array_count,
482 necp_kernel_policy_result *return_service_action,
483 necp_kernel_policy_service *return_service,
484 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
485 size_t netagent_array_count,
486 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
487 size_t netagent_use_flags_array_count,
488 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
489 u_int32_t num_required_agent_types,
490 proc_t proc,
491 u_int16_t pf_tag,
492 necp_kernel_policy_id *skip_policy_id,
493 struct rtentry *rt,
494 necp_kernel_policy_result *return_drop_dest_policy_result,
495 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
496 u_int32_t *return_flow_divert_aggregate_unit,
497 struct socket *so,
498 int debug);
499 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);
500 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
501 static bool necp_kernel_ip_output_policies_reprocess(void);
502
503 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
504 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);
505 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
506 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
507 static bool necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits);
508 static bool necp_addr_is_empty(struct sockaddr *addr);
509 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);
510 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
511
512 struct necp_uuid_id_mapping {
513 LIST_ENTRY(necp_uuid_id_mapping) chain;
514 uuid_t uuid;
515 u_int32_t id;
516 os_refcnt_t refcount;
517 u_int32_t table_usecount; // Add to UUID policy table count
518 };
519 static size_t necp_num_uuid_app_id_mappings;
520 static bool necp_uuid_app_id_mappings_dirty;
521 #define NECP_UUID_APP_ID_HASH_SIZE 64
522 static u_long necp_uuid_app_id_hash_mask;
523 static u_long necp_uuid_app_id_hash_num_buckets;
524 static LIST_HEAD(necp_uuid_id_mapping_head, necp_uuid_id_mapping) * __counted_by(necp_uuid_app_id_hash_num_buckets) necp_uuid_app_id_hashtbl, necp_uuid_service_id_list; // App map is real hash table, service map is just mapping
525 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
526 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
527 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
528 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
529
530 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
531 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
532 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
533 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
534 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
535
536 struct necp_string_id_mapping {
537 LIST_ENTRY(necp_string_id_mapping) chain;
538 char *string __null_terminated;
539 necp_app_id id;
540 os_refcnt_t refcount;
541 };
542 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
543 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
544 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
545 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
546
547 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);
548 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
549 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
550
551 static u_int32_t necp_create_domain_trie(struct necp_domain_trie_list *list, struct necp_domain_trie_list *owner_list,
552 struct necp_domain_trie_request *necp_trie_request, size_t necp_trie_request_size);
553 static bool necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id);
554 static void necp_free_domain_trie(struct necp_domain_trie *trie);
555 static struct necp_domain_trie *necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id);
556 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);
557
558 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
559 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
560
561 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
562
563 static char * __null_terminated necp_create_trimmed_domain(char * __sized_by(length)string, size_t length);
564 static inline int necp_count_dots(char * __sized_by(length)string, size_t length);
565
566 static char * __null_terminated necp_copy_string(char * __sized_by(length)string, size_t length);
567 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);
568
569 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
570
571 #define MAX_ROUTE_RULE_INTERFACES 10
572 struct necp_route_rule {
573 LIST_ENTRY(necp_route_rule) chain;
574 u_int32_t id;
575 u_int32_t netagent_id;
576 u_int32_t control_unit;
577 u_int32_t match_netagent_id;
578 u_int32_t effective_type;
579 u_int8_t default_action;
580 u_int8_t cellular_action;
581 u_int8_t wifi_action;
582 u_int8_t wired_action;
583 u_int8_t expensive_action;
584 u_int8_t constrained_action;
585 u_int8_t companion_action;
586 u_int8_t vpn_action;
587 u_int exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
588 u_int8_t exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
589 os_refcnt_t refcount;
590 };
591 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
592 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);
593 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
594 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
595 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,
596 u_int32_t route_rule_id, u_int32_t *interface_type_denied);
597 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);
598 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
599 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);
600 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
601 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
602
603 #define MAX_AGGREGATE_ROUTE_RULES 16
604 struct necp_aggregate_route_rule {
605 LIST_ENTRY(necp_aggregate_route_rule) chain;
606 u_int32_t id;
607 u_int32_t rule_ids[MAX_AGGREGATE_ROUTE_RULES];
608 };
609 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
610 static u_int32_t necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids);
611
612 // Sysctl definitions
613 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
614 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
615 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
616
617 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
618 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
619 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
620 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
621 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
622 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
623 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
624 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", "");
625 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", "");
626 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", "");
627 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
628 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, "");
629 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
630 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
631 SYSCTL_INT(_net_necp, NECPCTL_TRIE_COUNT, trie_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_trie_count, 0, "");
632
633 static struct necp_drop_dest_policy necp_drop_dest_policy;
634 static int necp_drop_dest_debug = 0; // 0: off, 1: match, >1: every evaluation
635 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
636
637 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
638 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
639 0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
640
641 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
642
643 /*
644 * data tracing control -
645 *
646 * necp_data_tracing_level : 1 for brief trace, 2 for policy details, 3 for condition details
647 * necp_data_tracing_port : match traffic with specified port
648 * necp_data_tracing_proto : match traffic with specified protocol
649 * necp_data_tracing_pid : match traffic with specified pid (only applied at socket level)
650 * necp_data_tracing_ifindex : match traffic on specified ifindex
651 * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched. Default is 0 to trace traffic if any specified attributes matched.
652 * data_tracing_session_order : match policies in the specified session - log traffic that hit these policies
653 * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
654 */
655 static int necp_data_tracing_level = 0;
656 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
657
658 static int necp_data_tracing_port = 0;
659 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
660
661 static int necp_data_tracing_proto = 0;
662 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
663
664 static int necp_data_tracing_pid = 0;
665 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
666
667 static int necp_data_tracing_ifindex = 0;
668 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
669
670 static int necp_data_tracing_match_all = 0;
671 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
672
673 static int necp_data_tracing_session_order = 0;
674 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
675
676 static int necp_data_tracing_policy_order = 0;
677 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
678
679 #define NECP_DATA_TRACE_LEVEL_BRIEF 1
680 #define NECP_DATA_TRACE_LEVEL_POLICY 2
681 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
682 #define NECP_DATA_TRACE_LEVEL_DP 4
683
684 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
685 (pid == necp_data_tracing_pid)
686 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
687 (protocol == necp_data_tracing_proto)
688 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
689 (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
690 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
691 (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
692 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
693 (ifindex == necp_data_tracing_ifindex)
694
695 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
696 ((necp_data_tracing_level && \
697 ((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
698 (necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
699 (necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
700 (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)
701
702 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
703 ((necp_data_tracing_level && \
704 ((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
705 (!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
706 (!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
707 (!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)
708
709 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
710 (necp_data_tracing_match_all ? \
711 NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
712 NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
713
714 #define NECP_DATA_TRACE_ON(debug) (debug)
715 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
716 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
717 #define NECP_DATA_TRACE_DP_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_CONDITION)
718
719 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
720
721 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
722 if (NECP_DATA_TRACE_ON(debug)) { \
723 char laddr_str[MAX_IPv6_STR_LEN]; \
724 char raddr_str[MAX_IPv6_STR_LEN]; \
725 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>", \
726 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); \
727 }
728
729 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
730 if (NECP_DATA_TRACE_ON(debug)) { \
731 char laddr_str[MAX_IPv6_STR_LEN]; \
732 char raddr_str[MAX_IPv6_STR_LEN]; \
733 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>", \
734 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); \
735 }
736
737 #define NECP_DATA_TRACE_LOG_SOCKET_DP(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
738 if (NECP_DATA_TRACE_ON(debug)) { \
739 char laddr_str[MAX_IPv6_STR_LEN]; \
740 char raddr_str[MAX_IPv6_STR_LEN]; \
741 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>", \
742 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); \
743 }
744
745 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
746 if (NECP_DATA_TRACE_ON(debug)) { \
747 char laddr_str[MAX_IPv6_STR_LEN]; \
748 char raddr_str[MAX_IPv6_STR_LEN]; \
749 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)", \
750 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]); \
751 }
752
753 #define NECP_DATA_TRACE_LOG_SOCKET_BRIEF(debug, socket, caller, log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id) \
754 if (NECP_DATA_TRACE_ON(debug)) { \
755 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - <policy_id %d skip_policy_id %d> <cached policy_id %d skip_policy_id %d>", \
756 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id); \
757 }
758
759 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
760 if (NECP_DATA_TRACE_ON(debug)) { \
761 char laddr_str[MAX_IPv6_STR_LEN]; \
762 char raddr_str[MAX_IPv6_STR_LEN]; \
763 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>", \
764 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)); \
765 }
766
767 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
768 if (NECP_DATA_TRACE_ON(debug)) { \
769 char laddr_str[MAX_IPv6_STR_LEN]; \
770 char raddr_str[MAX_IPv6_STR_LEN]; \
771 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>", \
772 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); \
773 }
774
775 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
776 if (NECP_DATA_TRACE_ON(debug)) { \
777 char laddr_str[MAX_IPv6_STR_LEN]; \
778 char raddr_str[MAX_IPv6_STR_LEN]; \
779 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)", \
780 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]); \
781 }
782
783 #define NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, socket, caller, log_msg) \
784 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
785 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)", \
786 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); \
787 }
788
789 #define NECP_DATA_TRACE_LOG_POLICY_IP(debug, caller, log_msg) \
790 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
791 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)", \
792 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); \
793 }
794
795 #define NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
796 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
797 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)>", \
798 caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
799 }
800
801 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
802 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
803 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
804 caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
805 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
806 }
807
808 #define NECP_DATA_TRACE_LOG_CONDITION_IP(debug, caller, negate, name, val, input) \
809 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
810
811 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR(debug, caller, negate, name, val, input) \
812 NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
813
814
815 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
816 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
817 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)>", \
818 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
819 }
820
821 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
822 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
823 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
824 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
825 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
826 }
827
828 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, caller, negate, name, val, input) \
829 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val, 0, 0, input, 0, 0)
830
831 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, caller, negate, name, val, input) \
832 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
833
834 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
835 (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
836 addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
837
838 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
839 "INVALID",
840 "PASS",
841 "SKIP",
842 "DROP",
843 "SOCKET_DIVERT",
844 "SOCKET_FILTER",
845 "IP_TUNNEL",
846 "IP_FILTER",
847 "TRIGGER",
848 "TRIGGER_IF_NEEDED",
849 "TRIGGER_SCOPED",
850 "NO_TRIGGER_SCOPED",
851 "SOCKET_SCOPED",
852 "ROUTE_RULES",
853 "USE_NETAGENT",
854 "NETAGENT_SCOPED",
855 "SCOPED_DIRECT",
856 "ALLOW_UNENTITLED",
857 "REMOVE_NETAGENT"
858 };
859
860
861 #define NECP_DDE_ENTITLEMENT "com.apple.developer.media-device-discovery-extension"
862
863 static int necp_drop_loopback_count = 0;
864 SYSCTL_INT(_net_necp, OID_AUTO, drop_loopback_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_drop_loopback_count, 0, "");
865
866 static bool
necp_address_is_local_interface_address(union necp_sockaddr_union * addr)867 necp_address_is_local_interface_address(union necp_sockaddr_union *addr)
868 {
869 bool is_interface_address = false;
870 if (addr == NULL) {
871 return false;
872 }
873
874 // Clean up the address before comparison with interface addresses
875 // Transform remote_addr into the ifaddr form
876 // IPv6 Scope IDs are always embedded in the ifaddr list
877 struct sockaddr_storage remote_address_sanitized;
878 u_int ifscope = IFSCOPE_NONE;
879 (void)sa_copy(SA(addr), &remote_address_sanitized, &ifscope);
880 SIN(&remote_address_sanitized)->sin_port = 0;
881 if (remote_address_sanitized.ss_family == AF_INET6) {
882 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
883 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
884 }
885 }
886
887 // Check if remote address is an interface address
888 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
889 if (ifa != NULL && ifa->ifa_ifp != NULL) {
890 is_interface_address = true;
891 }
892 if (ifa != NULL) {
893 ifaddr_release(ifa);
894 ifa = NULL;
895 }
896
897 return is_interface_address;
898 }
899
900 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, addr, include_local_addresses) \
901 ((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)))
902
903 // Session order allocation
904 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)905 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
906 {
907 u_int32_t new_order = 0;
908
909 // For now, just allocate 1000 orders for each priority
910 if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
911 priority = NECP_SESSION_PRIORITY_DEFAULT;
912 }
913
914 // Use the control unit to decide the offset into the priority list
915 new_order = (control_unit) + ((priority - 1) * 1000);
916
917 return new_order;
918 }
919
920 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)921 necp_get_first_order_for_priority(u_int32_t priority)
922 {
923 if (priority == 0) {
924 return 0;
925 }
926 return ((priority - 1) * 1000) + 1;
927 }
928
929 // Sysctl handler
930 static int
931 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
932 {
933 #pragma unused(arg1, arg2)
934 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
935 necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
936 return error;
937 }
938
939 static int
940 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
941 {
942 #pragma unused(arg1, arg2)
943 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
944 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
945 return error;
946 }
947
948 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
949 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)950 _necp_process_drop_order_inner(kauth_cred_t cred)
951 {
952 if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
953 priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
954 return necp_drop_unentitled_order;
955 } else {
956 return 0;
957 }
958 }
959
960 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
961 #pragma GCC poison _necp_process_drop_order_inner
962
963 static int
964 sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS
965 {
966 #pragma unused(arg1, arg2)
967 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
968 necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
969 return error;
970 }
971
972 static inline bool
necp_socket_is_connected(struct inpcb * inp)973 necp_socket_is_connected(struct inpcb *inp)
974 {
975 return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
976 }
977
978
979 // Session fd
980
981 static int necp_session_op_close(struct fileglob *, vfs_context_t);
982
983 static const struct fileops necp_session_fd_ops = {
984 .fo_type = DTYPE_NETPOLICY,
985 .fo_read = fo_no_read,
986 .fo_write = fo_no_write,
987 .fo_ioctl = fo_no_ioctl,
988 .fo_select = fo_no_select,
989 .fo_close = necp_session_op_close,
990 .fo_drain = fo_no_drain,
991 .fo_kqfilter = fo_no_kqfilter,
992 };
993
994 static inline int
necp_is_platform_binary(proc_t proc)995 necp_is_platform_binary(proc_t proc)
996 {
997 return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
998 }
999
1000 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)1001 necp_check_drop_all_bypass_result(proc_t proc)
1002 {
1003 if (proc == NULL) {
1004 proc = current_proc();
1005 if (proc == NULL) {
1006 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1007 }
1008 }
1009
1010 #if defined(XNU_TARGET_OS_OSX)
1011 const char *signing_id __null_terminated = NULL;
1012 const bool isConfigd = (necp_is_platform_binary(proc) &&
1013 (signing_id = cs_identity_get(proc)) &&
1014 (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
1015 (strcmp(signing_id, SIGNING_ID_CONFIGD) == 0));
1016 if (isConfigd) {
1017 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1018 }
1019 #endif
1020
1021 const task_t __single task = proc_task(proc);
1022 if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
1023 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1024 } else {
1025 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1026 }
1027 }
1028
1029 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)1030 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
1031 {
1032 #pragma unused(uap)
1033 int error = 0;
1034 struct necp_session *session = NULL;
1035 struct fileproc * __single fp = NULL;
1036 int fd = -1;
1037 uid_t uid = kauth_cred_getuid(kauth_cred_get());
1038
1039 if (!necp_is_platform_binary(p)) {
1040 NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
1041 error = EACCES;
1042 goto done;
1043 }
1044
1045 if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
1046 NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
1047 error = EACCES;
1048 goto done;
1049 }
1050
1051 error = falloc(p, &fp, &fd);
1052 if (error != 0) {
1053 goto done;
1054 }
1055
1056 session = necp_create_session();
1057 if (session == NULL) {
1058 error = ENOMEM;
1059 goto done;
1060 }
1061
1062 fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
1063 fp->fp_glob->fg_flag = 0;
1064 fp->fp_glob->fg_ops = &necp_session_fd_ops;
1065 fp_set_data(fp, session);
1066
1067 proc_fdlock(p);
1068 procfdtbl_releasefd(p, fd, NULL);
1069 fp_drop(p, fd, fp, 1);
1070 proc_fdunlock(p);
1071
1072 *retval = fd;
1073 done:
1074 if (error != 0) {
1075 if (fp != NULL) {
1076 fp_free(p, fd, fp);
1077 fp = NULL;
1078 }
1079 }
1080
1081 return error;
1082 }
1083
1084 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)1085 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
1086 {
1087 #pragma unused(ctx)
1088 struct necp_session *session = (struct necp_session *)fg_get_data(fg);
1089 fg_set_data(fg, NULL);
1090
1091 if (session != NULL) {
1092 necp_policy_mark_all_for_deletion(session);
1093 necp_policy_apply_all(session);
1094 necp_delete_session(session);
1095 return 0;
1096 } else {
1097 return ENOENT;
1098 }
1099 }
1100
1101 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)1102 necp_session_find_from_fd(struct proc *p, int fd,
1103 struct fileproc **fpp, struct necp_session **session)
1104 {
1105 struct fileproc * __single fp = NULL;
1106 int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
1107
1108 if (error == 0) {
1109 *fpp = fp;
1110 *session = (struct necp_session *)fp_get_data(fp);
1111 if ((*session)->necp_fd_type != necp_fd_type_session) {
1112 // Not a client fd, ignore
1113 fp_drop(p, fd, fp, 0);
1114 error = EINVAL;
1115 }
1116 }
1117
1118 return error;
1119 }
1120
1121 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1122 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1123 {
1124 int error = 0;
1125 u_int8_t * __indexable tlv_buffer = NULL;
1126
1127 if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
1128 NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1129 error = EINVAL;
1130 goto done;
1131 }
1132
1133 if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
1134 NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1135 error = EINVAL;
1136 goto done;
1137 }
1138
1139 if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
1140 error = ENOMEM;
1141 goto done;
1142 }
1143
1144 error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
1145 if (error != 0) {
1146 NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1147 goto done;
1148 }
1149
1150 necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1151 if (error != 0) {
1152 NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1153 goto done;
1154 }
1155
1156 error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1157 if (error != 0) {
1158 NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1159 goto done;
1160 }
1161
1162 done:
1163 if (tlv_buffer != NULL) {
1164 kfree_data(tlv_buffer, uap->in_buffer_length);
1165 tlv_buffer = NULL;
1166 }
1167 *retval = error;
1168
1169 return error;
1170 }
1171
1172 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1173 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1174 {
1175 int error = 0;
1176 u_int8_t * __indexable response = NULL;
1177
1178 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1179 NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1180 error = EINVAL;
1181 goto done;
1182 }
1183
1184 necp_policy_id policy_id = 0;
1185 error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1186 if (error != 0) {
1187 NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1188 goto done;
1189 }
1190
1191 struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1192 if (policy == NULL || policy->pending_deletion) {
1193 NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1194 error = ENOENT;
1195 goto done;
1196 }
1197
1198 u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1199 u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1200 u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1201
1202 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1203 NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1204 error = EINVAL;
1205 goto done;
1206 }
1207
1208 if (response_size > NECP_MAX_POLICY_SIZE) {
1209 NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1210 error = EINVAL;
1211 goto done;
1212 }
1213
1214 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1215 if (response == NULL) {
1216 error = ENOMEM;
1217 goto done;
1218 }
1219
1220 u_int8_t *cursor = response;
1221 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1222 if (result_tlv_size) {
1223 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, (void *)&policy->result, response, response_size);
1224 }
1225 if (policy->conditions_size) {
1226 memcpy(response + (cursor - response), policy->conditions, policy->conditions_size);
1227 }
1228
1229 error = copyout(response, uap->out_buffer, response_size);
1230 if (error != 0) {
1231 NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1232 goto done;
1233 }
1234
1235 done:
1236 if (response != NULL) {
1237 kfree_data(response, response_size);
1238 response = NULL;
1239 }
1240 *retval = error;
1241
1242 return error;
1243 }
1244
1245 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1246 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1247 {
1248 int error = 0;
1249
1250 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1251 NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1252 error = EINVAL;
1253 goto done;
1254 }
1255
1256 necp_policy_id delete_policy_id = 0;
1257 error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1258 if (error != 0) {
1259 NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1260 goto done;
1261 }
1262
1263 struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1264 if (policy == NULL || policy->pending_deletion) {
1265 NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1266 error = ENOENT;
1267 goto done;
1268 }
1269
1270 necp_policy_mark_for_deletion(session, policy);
1271 done:
1272 *retval = error;
1273 return error;
1274 }
1275
1276 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1277 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1278 {
1279 #pragma unused(uap)
1280 necp_policy_apply_all(session);
1281 *retval = 0;
1282 return 0;
1283 }
1284
1285 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1286 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1287 {
1288 u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1289 u_int32_t response_size = 0;
1290 u_int8_t * __indexable response = NULL;
1291 int num_policies = 0;
1292 int cur_policy_index = 0;
1293 int error = 0;
1294 struct necp_session_policy *policy;
1295
1296 LIST_FOREACH(policy, &session->policies, chain) {
1297 if (!policy->pending_deletion) {
1298 num_policies++;
1299 }
1300 }
1301
1302 if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1303 NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1304 error = EINVAL;
1305 goto done;
1306 }
1307
1308 response_size = num_policies * tlv_size;
1309 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1310 NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1311 error = EINVAL;
1312 goto done;
1313 }
1314
1315 // Create a response with one Policy ID TLV for each policy
1316 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1317 if (response == NULL) {
1318 error = ENOMEM;
1319 goto done;
1320 }
1321
1322 u_int8_t *cursor = response;
1323 LIST_FOREACH(policy, &session->policies, chain) {
1324 if (!policy->pending_deletion && cur_policy_index < num_policies) {
1325 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1326 cur_policy_index++;
1327 }
1328 }
1329
1330 error = copyout(response, uap->out_buffer, response_size);
1331 if (error != 0) {
1332 NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1333 goto done;
1334 }
1335
1336 done:
1337 if (response != NULL) {
1338 kfree_data(response, response_size);
1339 response = NULL;
1340 }
1341 *retval = error;
1342
1343 return error;
1344 }
1345
1346
1347 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1348 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1349 {
1350 #pragma unused(uap)
1351 necp_policy_mark_all_for_deletion(session);
1352 *retval = 0;
1353 return 0;
1354 }
1355
1356 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1357 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1358 {
1359 int error = 0;
1360 struct necp_session_policy *policy = NULL;
1361 struct necp_session_policy *temp_policy = NULL;
1362
1363 if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1364 NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1365 error = EINVAL;
1366 goto done;
1367 }
1368
1369 necp_session_priority requested_session_priority = 0;
1370 error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1371 if (error != 0) {
1372 NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1373 goto done;
1374 }
1375
1376 // Enforce special session priorities with entitlements
1377 if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1378 requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1379 requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1380 requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1381 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1382 if (cred_result != 0) {
1383 NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1384 error = EPERM;
1385 goto done;
1386 }
1387 }
1388
1389 if (session->session_priority != requested_session_priority) {
1390 session->session_priority = requested_session_priority;
1391 session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1392 session->dirty = TRUE;
1393
1394 // Mark all policies as needing updates
1395 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1396 policy->pending_update = TRUE;
1397 }
1398 }
1399
1400 done:
1401 *retval = error;
1402 return error;
1403 }
1404
1405 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1406 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1407 {
1408 #pragma unused(uap)
1409 session->proc_locked = TRUE;
1410 *retval = 0;
1411 return 0;
1412 }
1413
1414 static int
necp_session_register_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1415 necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1416 {
1417 int error = 0;
1418 struct necp_service_registration *new_service = NULL;
1419
1420 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1421 NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1422 error = EINVAL;
1423 goto done;
1424 }
1425
1426 uuid_t service_uuid;
1427 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1428 if (error != 0) {
1429 NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1430 goto done;
1431 }
1432
1433 new_service = kalloc_type(struct necp_service_registration,
1434 Z_WAITOK | Z_ZERO | Z_NOFAIL);
1435
1436 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1437 new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1438 LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1439 LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1440 lck_rw_done(&necp_kernel_policy_lock);
1441
1442 done:
1443 *retval = error;
1444 return error;
1445 }
1446
1447 static int
necp_session_unregister_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1448 necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1449 {
1450 int error = 0;
1451 struct necp_service_registration * __single service = NULL;
1452 struct necp_service_registration *temp_service = NULL;
1453 struct necp_uuid_id_mapping *mapping = NULL;
1454
1455 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1456 NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1457 error = EINVAL;
1458 goto done;
1459 }
1460
1461 uuid_t service_uuid;
1462 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1463 if (error != 0) {
1464 NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1465 goto done;
1466 }
1467
1468 // Remove all matching services for this session
1469 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1470 mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1471 if (mapping != NULL) {
1472 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1473 if (service->service_id == mapping->id) {
1474 LIST_REMOVE(service, session_chain);
1475 LIST_REMOVE(service, kernel_chain);
1476 kfree_type(struct necp_service_registration, service);
1477 }
1478 }
1479 necp_remove_uuid_service_id_mapping(service_uuid);
1480 }
1481 lck_rw_done(&necp_kernel_policy_lock);
1482
1483 done:
1484 *retval = error;
1485 return error;
1486 }
1487
1488 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1489 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1490 {
1491 #pragma unused(session)
1492 int error = 0;
1493
1494 if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1495 NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1496 error = EINVAL;
1497 goto done;
1498 }
1499
1500 error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1501 done:
1502 *retval = error;
1503 return error;
1504 }
1505
1506 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1507 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1508 {
1509 int error = 0;
1510 struct net_bloom_filter *bloom_filter = NULL;
1511 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1512 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1513
1514 if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1515 in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1516 uap->in_buffer == 0) {
1517 NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1518 error = EINVAL;
1519 goto done;
1520 }
1521
1522 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1523 NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1524 error = EINVAL;
1525 goto done;
1526 }
1527
1528 bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1529 if (bloom_filter == NULL) {
1530 NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1531 error = ENOMEM;
1532 goto done;
1533 }
1534
1535 error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1536 if (error != 0) {
1537 NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1538 goto done;
1539 }
1540
1541 size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1542 if (expected_filter_size != in_buffer_length) {
1543 NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1544 error = EINVAL;
1545 goto done;
1546 }
1547
1548 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1549 u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1550 lck_rw_done(&necp_kernel_policy_lock);
1551
1552 if (filter_id == 0) {
1553 error = ENOMEM;
1554 } else {
1555 // Bloom filter is taken over by the new filter entry, clear the local pointer
1556 bloom_filter = NULL;
1557
1558 error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1559 if (error != 0) {
1560 NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1561 goto done;
1562 }
1563 }
1564
1565 done:
1566 *retval = error;
1567 if (error != 0 && bloom_filter != NULL) {
1568 uint8_t * __single filter_buffer = (uint8_t *)bloom_filter;
1569 kfree_data(filter_buffer, in_buffer_length);
1570 bloom_filter = NULL;
1571 }
1572 return error;
1573 }
1574
1575 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1576 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1577 {
1578 int error = 0;
1579
1580 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1581 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1582 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1583 error = EINVAL;
1584 goto done;
1585 }
1586
1587 u_int32_t filter_id;
1588 error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1589 if (error != 0) {
1590 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1591 goto done;
1592 }
1593
1594 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1595 bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1596 if (!removed) {
1597 error = ENOENT;
1598 }
1599 lck_rw_done(&necp_kernel_policy_lock);
1600
1601 done:
1602 *retval = error;
1603 return error;
1604 }
1605
1606 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1607 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1608 {
1609 #pragma unused(uap)
1610
1611 struct necp_domain_filter * __single filter = NULL;
1612 struct necp_domain_filter *temp_filter = NULL;
1613 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1614 if (os_ref_release_locked(&filter->refcount) == 0) {
1615 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1616 LIST_REMOVE(filter, chain);
1617 lck_rw_done(&necp_kernel_policy_lock);
1618 LIST_REMOVE(filter, owner_chain);
1619 net_bloom_filter_destroy(filter->filter);
1620 kfree_type(struct necp_domain_filter, filter);
1621 }
1622 }
1623
1624 *retval = 0;
1625 return 0;
1626 }
1627
1628 static int
necp_session_add_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1629 necp_session_add_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1630 {
1631 int error = 0;
1632
1633 struct necp_domain_trie_request *domain_trie_request = NULL;
1634 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1635 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1636
1637 if (in_buffer_length < sizeof(struct necp_domain_trie_request) ||
1638 in_buffer_length > NECP_MAX_DOMAIN_TRIE_SIZE ||
1639 uap->in_buffer == 0) {
1640 NECPLOG(LOG_ERR, "necp_session_add_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1641 error = EINVAL;
1642 goto done;
1643 }
1644
1645 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1646 NECPLOG(LOG_ERR, "necp_session_add_domain_trie buffer not large enough (%zu)", (size_t)out_buffer_length);
1647 error = EINVAL;
1648 goto done;
1649 }
1650
1651 domain_trie_request = (struct necp_domain_trie_request *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1652 if (domain_trie_request == NULL) {
1653 NECPLOG(LOG_ERR, "necp_session_add_domain_trie allocate trie request error (%zu)", in_buffer_length);
1654 error = ENOMEM;
1655 goto done;
1656 }
1657
1658 error = copyin(uap->in_buffer, domain_trie_request, in_buffer_length);
1659 if (error != 0) {
1660 NECPLOG(LOG_ERR, "necp_session_add_domain_trie filter copyin error (%d)", error);
1661 goto done;
1662 }
1663
1664 NECPLOG(LOG_INFO, "necp_session_add_domain_trie received %zu bytes <trie mem size %d>", in_buffer_length, domain_trie_request->total_mem_size);
1665
1666 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1667 u_int32_t id = necp_create_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, domain_trie_request, in_buffer_length);
1668 lck_rw_done(&necp_kernel_policy_lock);
1669
1670 if (id == 0) {
1671 error = ENOMEM;
1672 } else {
1673 error = copyout(&id, uap->out_buffer, sizeof(id));
1674 if (error != 0) {
1675 NECPLOG(LOG_ERR, "necp_session_add_domain_trie ID copyout error (%d)", error);
1676 goto done;
1677 }
1678 }
1679
1680 done:
1681 *retval = error;
1682 if (error != 0 && domain_trie_request != NULL) {
1683 uint8_t * __single domain_buffer = (uint8_t *)domain_trie_request;
1684 kfree_data(domain_buffer, in_buffer_length);
1685 domain_trie_request = NULL;
1686 }
1687 return error;
1688 }
1689
1690 static int
necp_session_remove_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1691 necp_session_remove_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1692 {
1693 int error = 0;
1694
1695 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1696 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1697 NECPLOG(LOG_ERR, "necp_session_remove_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1698 error = EINVAL;
1699 goto done;
1700 }
1701
1702 u_int32_t id;
1703 error = copyin(uap->in_buffer, &id, sizeof(id));
1704 if (error != 0) {
1705 NECPLOG(LOG_ERR, "necp_session_remove_domain_trie uuid copyin error (%d)", error);
1706 goto done;
1707 }
1708
1709 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1710 bool removed = necp_remove_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, id);
1711 if (!removed) {
1712 error = ENOENT;
1713 }
1714 lck_rw_done(&necp_kernel_policy_lock);
1715
1716 done:
1717 *retval = error;
1718 return error;
1719 }
1720
1721 static int
necp_session_remove_all_domain_tries(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1722 necp_session_remove_all_domain_tries(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1723 {
1724 #pragma unused(uap)
1725 struct necp_domain_trie* __single trie = NULL;
1726 struct necp_domain_trie* __single temp_trie = NULL;
1727 LIST_FOREACH_SAFE(trie, &session->domain_tries, owner_chain, temp_trie) {
1728 if (os_ref_release_locked(&trie->refcount) == 0) {
1729 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1730 LIST_REMOVE(trie, chain);
1731 lck_rw_done(&necp_kernel_policy_lock);
1732 LIST_REMOVE(trie, owner_chain);
1733 necp_free_domain_trie(trie);
1734 }
1735 }
1736 *retval = 0;
1737 return 0;
1738 }
1739
1740 static int
necp_session_trie_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1741 necp_session_trie_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1742 {
1743 #pragma unused(session)
1744
1745 int error = 0;
1746
1747 uint8_t request_buffer[2000] = { 0 };
1748 uint8_t *ptr = NULL;
1749 uint32_t count = 0;
1750 int output_length = 0;
1751
1752 lck_rw_lock_shared(&necp_kernel_policy_lock);
1753 count = necp_trie_count;
1754 lck_rw_done(&necp_kernel_policy_lock);
1755
1756 if (count == 0) {
1757 error = ENOENT;
1758 goto done;
1759 }
1760
1761 output_length = sizeof(count) + (count * sizeof(struct necp_domain_trie_request)); // first byte contains count
1762 if (output_length > uap->out_buffer_length) {
1763 NECPLOG(LOG_ERR, "necp_session_trie_dump_all out_buffer not large enough for %zu", (size_t)output_length);
1764 error = EINVAL;
1765 goto done;
1766 }
1767 if (output_length > sizeof(request_buffer)) {
1768 NECPLOG(LOG_ERR, "necp_session_trie_dump_all temporary buffer not large enough for %zu", (size_t)output_length);
1769 error = EINVAL;
1770 goto done;
1771 }
1772
1773 memcpy(request_buffer, (u_int8_t *)&count, sizeof(count));
1774 ptr = request_buffer + sizeof(count);
1775
1776 lck_rw_lock_shared(&necp_kernel_policy_lock);
1777 struct necp_domain_trie* __single trie = NULL;
1778 LIST_FOREACH(trie, &necp_global_domain_trie_list, chain) {
1779 if (trie->trie_request != NULL) {
1780 memcpy((u_int8_t *)ptr, (u_int8_t *)trie->trie_request, sizeof(struct necp_domain_trie_request));
1781 ptr += sizeof(struct necp_domain_trie_request);
1782 }
1783 }
1784 lck_rw_done(&necp_kernel_policy_lock);
1785
1786 error = copyout(request_buffer, uap->out_buffer, output_length);
1787
1788 done:
1789 *retval = error;
1790 return error;
1791 }
1792
1793 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1794 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1795 {
1796 struct fileproc * __single fp;
1797 int error = 0;
1798 int return_value = 0;
1799 struct necp_session * __single session = NULL;
1800
1801 error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1802 if (error != 0) {
1803 NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1804 return error;
1805 }
1806
1807 NECP_SESSION_LOCK(session);
1808
1809 if (session->proc_locked) {
1810 // Verify that the calling process is allowed to do actions
1811 uuid_t proc_uuid;
1812 proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1813 if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1814 error = EPERM;
1815 goto done;
1816 }
1817 } else {
1818 // If not locked, update the proc_uuid and proc_pid of the session
1819 proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1820 session->proc_pid = proc_pid(current_proc());
1821 }
1822
1823 u_int32_t action = uap->action;
1824 switch (action) {
1825 case NECP_SESSION_ACTION_POLICY_ADD: {
1826 return_value = necp_session_add_policy(session, uap, retval);
1827 break;
1828 }
1829 case NECP_SESSION_ACTION_POLICY_GET: {
1830 return_value = necp_session_get_policy(session, uap, retval);
1831 break;
1832 }
1833 case NECP_SESSION_ACTION_POLICY_DELETE: {
1834 return_value = necp_session_delete_policy(session, uap, retval);
1835 break;
1836 }
1837 case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1838 return_value = necp_session_apply_all(session, uap, retval);
1839 break;
1840 }
1841 case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1842 return_value = necp_session_list_all(session, uap, retval);
1843 break;
1844 }
1845 case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1846 return_value = necp_session_delete_all(session, uap, retval);
1847 break;
1848 }
1849 case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1850 return_value = necp_session_set_session_priority(session, uap, retval);
1851 break;
1852 }
1853 case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1854 return_value = necp_session_lock_to_process(session, uap, retval);
1855 break;
1856 }
1857 case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1858 return_value = necp_session_register_service(session, uap, retval);
1859 break;
1860 }
1861 case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1862 return_value = necp_session_unregister_service(session, uap, retval);
1863 break;
1864 }
1865 case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1866 return_value = necp_session_dump_all(session, uap, retval);
1867 break;
1868 }
1869 case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1870 return_value = necp_session_add_domain_filter(session, uap, retval);
1871 break;
1872 }
1873 case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1874 return_value = necp_session_remove_domain_filter(session, uap, retval);
1875 break;
1876 }
1877 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1878 return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1879 break;
1880 }
1881 case NECP_SESSION_ACTION_ADD_DOMAIN_TRIE: {
1882 return_value = necp_session_add_domain_trie(session, uap, retval);
1883 break;
1884 }
1885 case NECP_SESSION_ACTION_REMOVE_DOMAIN_TRIE: {
1886 return_value = necp_session_remove_domain_trie(session, uap, retval);
1887 break;
1888 }
1889 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_TRIES: {
1890 return_value = necp_session_remove_all_domain_tries(session, uap, retval);
1891 break;
1892 }
1893 case NECP_SESSION_ACTION_TRIE_DUMP_ALL: {
1894 return_value = necp_session_trie_dump_all(session, uap, retval);
1895 break;
1896 }
1897 default: {
1898 NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1899 return_value = EINVAL;
1900 break;
1901 }
1902 }
1903
1904 done:
1905 NECP_SESSION_UNLOCK(session);
1906 fp_drop(p, uap->necp_fd, fp, 0);
1907 return return_value;
1908 }
1909
1910 struct necp_resolver_key_state {
1911 const struct ccdigest_info *digest_info;
1912 uint8_t key[CCSHA256_OUTPUT_SIZE];
1913 };
1914 static struct necp_resolver_key_state s_necp_resolver_key_state;
1915
1916 static void
necp_generate_resolver_key(void)1917 necp_generate_resolver_key(void)
1918 {
1919 s_necp_resolver_key_state.digest_info = ccsha256_di();
1920 cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1921 }
1922
1923 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)1924 necp_sign_update_context(const struct ccdigest_info *di,
1925 cchmac_ctx_t ctx,
1926 uuid_t client_id,
1927 u_int32_t sign_type,
1928 u_int8_t *data,
1929 size_t data_length)
1930 {
1931 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1932 const char * __null_terminated context_string = "NECP Resolver Binder";
1933 uint8_t separator = 0;
1934 cchmac_update(di, ctx, sizeof(context), context);
1935 cchmac_update(di, ctx, strlen(context_string), __unsafe_null_terminated_to_indexable(context_string));
1936 cchmac_update(di, ctx, sizeof(separator), &separator);
1937 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1938 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1939 cchmac_update(di, ctx, data_length, data);
1940 }
1941
1942 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)1943 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1944 u_int8_t *data, size_t data_length,
1945 u_int8_t *tag, size_t *out_tag_length)
1946 {
1947 if (s_necp_resolver_key_state.digest_info == NULL) {
1948 return EINVAL;
1949 }
1950
1951 if (data == NULL ||
1952 data_length == 0 ||
1953 tag == NULL ||
1954 out_tag_length == NULL) {
1955 return EINVAL;
1956 }
1957
1958 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1959 if (*out_tag_length < required_tag_length) {
1960 return ERANGE;
1961 }
1962
1963 *out_tag_length = required_tag_length;
1964
1965 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1966 s_necp_resolver_key_state.digest_info->block_size, ctx);
1967 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1968 sizeof(s_necp_resolver_key_state.key),
1969 s_necp_resolver_key_state.key);
1970 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1971 ctx, client_id, sign_type, data, data_length);
1972 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1973
1974 return 0;
1975 }
1976
1977 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)1978 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1979 u_int8_t * __sized_by(data_length)data, size_t data_length,
1980 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1981 {
1982 if (s_necp_resolver_key_state.digest_info == NULL) {
1983 return false;
1984 }
1985
1986 if (data == NULL ||
1987 data_length == 0 ||
1988 tag == NULL ||
1989 tag_length == 0) {
1990 return false;
1991 }
1992
1993 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1994 if (tag_length != required_tag_length) {
1995 return false;
1996 }
1997
1998 uint8_t actual_tag[required_tag_length];
1999
2000 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
2001 s_necp_resolver_key_state.digest_info->block_size, ctx);
2002 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
2003 sizeof(s_necp_resolver_key_state.key),
2004 s_necp_resolver_key_state.key);
2005 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
2006 ctx, client_id, sign_type, data, data_length);
2007 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
2008
2009 return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
2010 }
2011
2012 struct necp_application_id_key_state {
2013 const struct ccdigest_info *digest_info;
2014 uint8_t key[CCSHA256_OUTPUT_SIZE];
2015 };
2016 static struct necp_application_id_key_state s_necp_application_id_key_state;
2017
2018 static void
necp_generate_application_id_key(void)2019 necp_generate_application_id_key(void)
2020 {
2021 s_necp_application_id_key_state.digest_info = ccsha256_di();
2022 cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
2023 }
2024
2025 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)2026 necp_sign_application_id_update_context(const struct ccdigest_info *di,
2027 cchmac_ctx_t ctx,
2028 uuid_t client_id,
2029 u_int32_t sign_type)
2030 {
2031 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
2032 const char context_string[] = "NECP Application ID";
2033 uint8_t separator = 0;
2034 cchmac_update(di, ctx, sizeof(context), context);
2035 cchmac_update(di, ctx, sizeof(context_string) - 1, context_string);
2036 cchmac_update(di, ctx, sizeof(separator), &separator);
2037 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
2038 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
2039 }
2040
2041 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)2042 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
2043 u_int8_t *__counted_by(*out_tag_length)tag, size_t *out_tag_length)
2044 {
2045 if (s_necp_application_id_key_state.digest_info == NULL) {
2046 return EINVAL;
2047 }
2048
2049 if (tag == NULL ||
2050 out_tag_length == NULL) {
2051 return EINVAL;
2052 }
2053
2054 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2055 if (*out_tag_length < required_tag_length) {
2056 return ERANGE;
2057 }
2058
2059 *out_tag_length = required_tag_length;
2060
2061 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2062 s_necp_application_id_key_state.digest_info->block_size, ctx);
2063 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2064 sizeof(s_necp_application_id_key_state.key),
2065 s_necp_application_id_key_state.key);
2066 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2067 ctx, client_id, sign_type);
2068 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
2069
2070 return 0;
2071 }
2072
2073 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)2074 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
2075 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
2076 {
2077 if (s_necp_application_id_key_state.digest_info == NULL) {
2078 return false;
2079 }
2080
2081 if (tag == NULL ||
2082 tag_length == 0) {
2083 return false;
2084 }
2085
2086 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2087 if (tag_length != required_tag_length) {
2088 return false;
2089 }
2090
2091 uint8_t actual_tag[required_tag_length];
2092
2093 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2094 s_necp_application_id_key_state.digest_info->block_size, ctx);
2095 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2096 sizeof(s_necp_application_id_key_state.key),
2097 s_necp_application_id_key_state.key);
2098 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2099 ctx, client_id, sign_type);
2100 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
2101
2102 return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
2103 }
2104
2105 void
necp_init(void)2106 necp_init(void)
2107 {
2108 necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
2109 necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
2110
2111 necp_client_init();
2112
2113 TAILQ_INIT(&necp_session_list);
2114
2115 LIST_INIT(&necp_kernel_socket_policies);
2116 LIST_INIT(&necp_kernel_ip_output_policies);
2117
2118 LIST_INIT(&necp_account_id_list);
2119
2120 LIST_INIT(&necp_uuid_service_id_list);
2121
2122 LIST_INIT(&necp_registered_service_list);
2123
2124 LIST_INIT(&necp_route_rules);
2125 LIST_INIT(&necp_aggregate_route_rules);
2126
2127 LIST_INIT(&necp_global_domain_filter_list);
2128 LIST_INIT(&necp_global_domain_trie_list);
2129
2130 necp_generate_resolver_key();
2131 necp_generate_application_id_key();
2132
2133 necp_uuid_app_id_hashtbl = __unsafe_forge_bidi_indexable(struct necp_uuid_id_mapping_head *,
2134 hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask),
2135 NECP_UUID_APP_ID_HASH_SIZE * sizeof(void*));
2136 necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
2137 necp_num_uuid_app_id_mappings = 0;
2138 necp_uuid_app_id_mappings_dirty = FALSE;
2139
2140 necp_kernel_application_policies_condition_mask = 0;
2141 necp_kernel_socket_policies_condition_mask = 0;
2142 necp_kernel_ip_output_policies_condition_mask = 0;
2143
2144 necp_kernel_application_policies_count = 0;
2145 necp_kernel_socket_policies_count = 0;
2146 necp_kernel_socket_policies_non_app_count = 0;
2147 necp_kernel_ip_output_policies_count = 0;
2148 necp_kernel_ip_output_policies_non_id_count = 0;
2149
2150 necp_kernel_socket_policies_gencount = 1;
2151
2152 memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
2153 memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
2154 necp_kernel_socket_policies_app_layer_map = NULL;
2155
2156 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
2157 necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
2158 }
2159
2160 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)2161 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
2162 {
2163 struct kev_msg ev_msg;
2164 memset(&ev_msg, 0, sizeof(ev_msg));
2165
2166 ev_msg.vendor_code = KEV_VENDOR_APPLE;
2167 ev_msg.kev_class = KEV_NETWORK_CLASS;
2168 ev_msg.kev_subclass = KEV_NECP_SUBCLASS;
2169 ev_msg.event_code = KEV_NECP_POLICIES_CHANGED;
2170
2171 ev_msg.dv[0].data_ptr = necp_event_data;
2172 ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
2173 ev_msg.dv[1].data_length = 0;
2174
2175 kev_post_msg(&ev_msg);
2176 }
2177
2178 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)2179 necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor, u_int8_t type, u_int32_t length,
2180 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2181 {
2182 if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
2183 NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
2184 return false;
2185 }
2186 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2187 if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
2188 (uintptr_t)(next_tlv - buffer) > buffer_length) { // make sure the next TLV has enough room in buffer
2189 NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
2190 length, buffer_length);
2191 return false;
2192 }
2193 return true;
2194 }
2195
2196 u_int8_t * __counted_by(0)
2197 necp_buffer_write_tlv_if_different(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2198 u_int32_t length, const void * __sized_by(length)value, bool *updated,
2199 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2200 {
2201 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2202 u_int8_t * cursor = buffer + (cursor_ - buffer);
2203 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2204 // If we can't fit this TLV, return the current cursor
2205 return cursor;
2206 }
2207 u_int8_t * __indexable next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2208 if (*updated || *(u_int8_t *)(cursor) != type) {
2209 *(u_int8_t *)(cursor) = type;
2210 *updated = TRUE;
2211 }
2212 if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
2213 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2214 *updated = TRUE;
2215 }
2216 if (length > 0) {
2217 if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
2218 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2219 *updated = TRUE;
2220 }
2221 }
2222 return next_tlv;
2223 }
2224
2225 u_int8_t * __counted_by(0)
2226 necp_buffer_write_tlv(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2227 u_int32_t length, const void * __sized_by(length)value,
2228 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2229 {
2230 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2231 u_int8_t * cursor = buffer + (cursor_ - buffer);
2232 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2233 return NULL;
2234 }
2235 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2236 *(u_int8_t *)(cursor) = type;
2237 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2238 if (length > 0) {
2239 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2240 }
2241
2242 return next_tlv;
2243 }
2244
2245 static u_int8_t * __counted_by(0)
2246 necp_buffer_write_tlv_with_flags(u_int8_t * __counted_by(0)cursor_, u_int8_t type, u_int8_t flags,
2247 u_int32_t length, const void * __sized_by(length)value,
2248 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2249 {
2250 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2251 // Add one extra byte to 'length' to account for the flags byte for validation.
2252 u_int8_t * cursor = buffer + (cursor_ - buffer);
2253 if (!necp_buffer_write_tlv_validate(cursor, type, length + 1, buffer, buffer_length)) {
2254 return NULL;
2255 }
2256 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(flags) + sizeof(length) + length);
2257
2258 // TLV with flags format: type, length, flags, value (added 1 byte for the leading flags)
2259 *(u_int8_t *)(cursor) = type;
2260 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2261 *(u_int8_t *)(cursor + sizeof(type) + sizeof(length)) = flags;
2262 if (length > 0) {
2263 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length) + sizeof(flags)), value, length);
2264 }
2265
2266 return next_tlv;
2267 }
2268
2269 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)2270 necp_buffer_get_tlv_type(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2271 {
2272 u_int8_t * __indexable type = NULL;
2273 uint64_t end_offset = 0;
2274
2275 if (buffer == NULL ||
2276 os_add_overflow(tlv_offset, sizeof(u_int8_t), &end_offset) || buffer_length < end_offset) {
2277 return 0;
2278 }
2279
2280 type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
2281 return type ? *type : 0;
2282 }
2283
2284 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)2285 necp_buffer_get_tlv_length(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2286 {
2287 u_int32_t * __indexable length = NULL;
2288 uint64_t end_offset = 0;
2289
2290 if (buffer == NULL ||
2291 os_add_overflow(tlv_offset, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2292 return 0;
2293 }
2294
2295 length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
2296 return length ? *length : 0;
2297 }
2298
2299 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)2300 __necp_buffer_get_tlv_value(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset, u_int32_t * value_size)
2301 {
2302 u_int8_t * __indexable value = NULL;
2303 uint64_t end_offset = 0;
2304
2305 if (buffer == NULL) {
2306 return NULL;
2307 }
2308
2309 u_int32_t length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2310 if (length == 0) {
2311 return NULL;
2312 }
2313
2314 if (os_add3_overflow(tlv_offset, length, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2315 return NULL;
2316 }
2317
2318 if (value_size) {
2319 *value_size = length;
2320 }
2321
2322 value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2323 return value;
2324 }
2325
2326 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)2327 necp_buffer_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2328 {
2329 if (err != NULL) {
2330 *err = ENOENT;
2331 }
2332 if (offset < 0) {
2333 if (err != NULL) {
2334 *err = EINVAL;
2335 }
2336 return -1;
2337 }
2338 int cursor = offset;
2339 int next_cursor;
2340 u_int32_t curr_length;
2341 u_int8_t curr_type;
2342
2343 while (TRUE) {
2344 if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
2345 return -1;
2346 }
2347 if (!next) {
2348 curr_type = necp_buffer_get_tlv_type(buffer, buffer_length, cursor);
2349 } else {
2350 next = 0;
2351 curr_type = NECP_TLV_NIL;
2352 }
2353 curr_length = necp_buffer_get_tlv_length(buffer, buffer_length, cursor);
2354 if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
2355 return -1;
2356 }
2357
2358 next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
2359 if (curr_type == type) {
2360 // check if entire TLV fits inside buffer
2361 if (((u_int32_t)next_cursor) <= buffer_length) {
2362 if (err != NULL) {
2363 *err = 0;
2364 }
2365 return cursor;
2366 } else {
2367 return -1;
2368 }
2369 }
2370 cursor = next_cursor;
2371 }
2372 }
2373
2374 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)2375 necp_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2376 {
2377 int cursor = -1;
2378 if (buffer != NULL) {
2379 cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2380 }
2381 return cursor;
2382 }
2383
2384 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)2385 necp_get_tlv_at_offset(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2386 int tlv_offset, u_int32_t out_buffer_length, void * __indexable out_buffer, u_int32_t *value_size)
2387 {
2388 if (buffer == NULL) {
2389 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2390 return EINVAL;
2391 }
2392
2393 // Handle buffer parsing
2394
2395 // Validate that buffer has enough room for any TLV
2396 if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2397 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2398 buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2399 return EINVAL;
2400 }
2401
2402 // Validate that buffer has enough room for this TLV
2403 u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2404 if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2405 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2406 tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2407 return EINVAL;
2408 }
2409
2410 if (out_buffer != NULL && out_buffer_length > 0) {
2411 // Validate that out buffer is large enough for value
2412 if (out_buffer_length < tlv_length) {
2413 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2414 out_buffer_length, tlv_length);
2415 return EINVAL;
2416 }
2417
2418 // Get value pointer
2419 u_int8_t * __indexable tlv_value = necp_buffer_get_tlv_value(buffer, buffer_length, tlv_offset, NULL);
2420 if (tlv_value == NULL) {
2421 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2422 return ENOENT;
2423 }
2424
2425 // Copy value
2426 memcpy(out_buffer, tlv_value, tlv_length);
2427 }
2428
2429 // Copy out length
2430 if (value_size != NULL) {
2431 *value_size = tlv_length;
2432 }
2433
2434 return 0;
2435 }
2436
2437 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)2438 necp_get_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2439 int offset, u_int8_t type, u_int32_t buff_len, void * __indexable buff, u_int32_t *value_size)
2440 {
2441 int error = 0;
2442
2443 int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2444 if (tlv_offset < 0) {
2445 return error;
2446 }
2447
2448 return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2449 }
2450
2451 // Session Management
2452
2453 static struct necp_session *
necp_create_session(void)2454 necp_create_session(void)
2455 {
2456 struct necp_session *new_session = NULL;
2457
2458 new_session = kalloc_type(struct necp_session,
2459 Z_WAITOK | Z_ZERO | Z_NOFAIL);
2460
2461 new_session->necp_fd_type = necp_fd_type_session;
2462 new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2463 new_session->dirty = FALSE;
2464 LIST_INIT(&new_session->policies);
2465 LIST_INIT(&new_session->services);
2466 LIST_INIT(&new_session->domain_filters);
2467 LIST_INIT(&new_session->domain_tries);
2468 lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2469
2470 // Take the lock
2471 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2472
2473 // Find the next available control unit
2474 u_int32_t control_unit = 1;
2475 struct necp_session *next_session = NULL;
2476 TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2477 if (next_session->control_unit > control_unit) {
2478 // Found a gap, grab this control unit
2479 break;
2480 }
2481
2482 // Try the next control unit, loop around
2483 control_unit = next_session->control_unit + 1;
2484 }
2485
2486 new_session->control_unit = control_unit;
2487 new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2488
2489 if (next_session != NULL) {
2490 TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2491 } else {
2492 TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2493 }
2494
2495 necp_session_count++;
2496 lck_rw_done(&necp_kernel_policy_lock);
2497
2498 if (necp_debug) {
2499 NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2500 }
2501
2502 return new_session;
2503 }
2504
2505 static void
necp_delete_session(struct necp_session * session)2506 necp_delete_session(struct necp_session *session)
2507 {
2508 if (session != NULL) {
2509 struct necp_service_registration * __single service = NULL;
2510 struct necp_service_registration *temp_service = NULL;
2511 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
2512 LIST_REMOVE(service, session_chain);
2513 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2514 LIST_REMOVE(service, kernel_chain);
2515 lck_rw_done(&necp_kernel_policy_lock);
2516 kfree_type(struct necp_service_registration, service);
2517 }
2518 struct necp_domain_filter * __single filter = NULL;
2519 struct necp_domain_filter *temp_filter = NULL;
2520 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2521 if (os_ref_release_locked(&filter->refcount) == 0) {
2522 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2523 LIST_REMOVE(filter, chain);
2524 lck_rw_done(&necp_kernel_policy_lock);
2525 LIST_REMOVE(filter, owner_chain);
2526 net_bloom_filter_destroy(filter->filter);
2527 kfree_type(struct necp_domain_filter, filter);
2528 }
2529 }
2530 if (necp_debug) {
2531 NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2532 }
2533
2534 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2535 TAILQ_REMOVE(&necp_session_list, session, chain);
2536 necp_session_count--;
2537 lck_rw_done(&necp_kernel_policy_lock);
2538
2539 lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2540 kfree_type(struct necp_session, session);
2541 }
2542 }
2543
2544 // Session Policy Management
2545
2546 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2547 necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2548 {
2549 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2550 }
2551
2552 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2553 necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2554 {
2555 return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2556 }
2557
2558 static inline u_int8_t * __indexable
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2559 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2560 {
2561 return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2562 }
2563
2564 static bool
necp_policy_result_requires_route_rules(u_int8_t * __sized_by (length)buffer,u_int32_t length)2565 necp_policy_result_requires_route_rules(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2566 {
2567 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2568 if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2569 return TRUE;
2570 }
2571 return FALSE;
2572 }
2573
2574 static inline bool
_necp_address_is_valid(struct sockaddr * address)2575 _necp_address_is_valid(struct sockaddr *address)
2576 {
2577 if (address->sa_family == AF_INET) {
2578 return address->sa_len == sizeof(struct sockaddr_in);
2579 } else if (address->sa_family == AF_INET6) {
2580 return address->sa_len == sizeof(struct sockaddr_in6);
2581 } else {
2582 return FALSE;
2583 }
2584 }
2585
2586 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2587
2588 static bool
necp_policy_result_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,bool * is_pass_skip)2589 necp_policy_result_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, bool *is_pass_skip)
2590 {
2591 bool validated = FALSE;
2592 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2593 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2594 *is_pass_skip = FALSE;
2595 switch (type) {
2596 case NECP_POLICY_RESULT_PASS: {
2597 *is_pass_skip = TRUE;
2598 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2599 validated = TRUE;
2600 }
2601 break;
2602 }
2603 case NECP_POLICY_RESULT_DROP: {
2604 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2605 validated = TRUE;
2606 }
2607 break;
2608 }
2609 case NECP_POLICY_RESULT_ROUTE_RULES:
2610 case NECP_POLICY_RESULT_SCOPED_DIRECT:
2611 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2612 validated = TRUE;
2613 break;
2614 }
2615 case NECP_POLICY_RESULT_SKIP:
2616 *is_pass_skip = TRUE;
2617 case NECP_POLICY_RESULT_SOCKET_DIVERT:
2618 case NECP_POLICY_RESULT_SOCKET_FILTER: {
2619 if (parameter_length >= sizeof(u_int32_t)) {
2620 validated = TRUE;
2621 }
2622 break;
2623 }
2624 case NECP_POLICY_RESULT_IP_TUNNEL: {
2625 if (parameter_length > sizeof(u_int32_t)) {
2626 validated = TRUE;
2627 }
2628 break;
2629 }
2630 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2631 if (parameter_length > 0) {
2632 validated = TRUE;
2633 }
2634 break;
2635 }
2636 case NECP_POLICY_RESULT_USE_NETAGENT:
2637 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2638 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2639 if (parameter_length >= sizeof(uuid_t)) {
2640 validated = TRUE;
2641 }
2642 break;
2643 }
2644 default: {
2645 validated = FALSE;
2646 break;
2647 }
2648 }
2649
2650 if (necp_debug) {
2651 NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2652 }
2653
2654 return validated;
2655 }
2656
2657 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2658 necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2659 {
2660 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2661 }
2662
2663 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2664 necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2665 {
2666 return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2667 }
2668
2669 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2670 necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2671 {
2672 return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2673 }
2674
2675 static inline u_int8_t * __indexable
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2676 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2677 {
2678 return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2679 }
2680
2681 static inline bool
necp_policy_condition_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2682 necp_policy_condition_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2683 {
2684 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2685 }
2686
2687 static inline bool
necp_policy_condition_is_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2688 necp_policy_condition_is_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2689 {
2690 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2691 }
2692
2693 static inline bool
necp_policy_condition_is_real_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2694 necp_policy_condition_is_real_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2695 {
2696 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2697 }
2698
2699 static inline bool
necp_policy_condition_requires_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2700 necp_policy_condition_requires_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2701 {
2702 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2703 return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2704 }
2705
2706 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2707 necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2708 {
2709 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2710 u_int32_t condition_length = 0;
2711 pid_t *condition_value = NULL;
2712
2713 if (type == NECP_POLICY_CONDITION_PID) {
2714 condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2715 if (condition_length >= sizeof(pid_t)) {
2716 condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2717 return *condition_value == 0;
2718 }
2719 }
2720 return false;
2721 }
2722
2723 static bool
necp_policy_condition_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,u_int8_t policy_result_type)2724 necp_policy_condition_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, u_int8_t policy_result_type)
2725 {
2726 bool validated = FALSE;
2727 bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2728 policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2729 policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2730 policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2731 policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2732 policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2733 policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2734 policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2735 policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2736 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2737 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2738 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2739 u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2740 switch (type) {
2741 case NECP_POLICY_CONDITION_APPLICATION:
2742 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2743 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2744 condition_length >= sizeof(uuid_t) &&
2745 condition_value != NULL &&
2746 !uuid_is_null(condition_value)) {
2747 validated = TRUE;
2748 }
2749 break;
2750 }
2751 case NECP_POLICY_CONDITION_DOMAIN:
2752 case NECP_POLICY_CONDITION_ACCOUNT:
2753 case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2754 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2755 case NECP_POLICY_CONDITION_URL: {
2756 if (condition_length > 0) {
2757 validated = TRUE;
2758 }
2759 break;
2760 }
2761 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2762 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2763 validated = TRUE;
2764 }
2765 break;
2766 }
2767 case NECP_POLICY_CONDITION_DEFAULT:
2768 case NECP_POLICY_CONDITION_ALL_INTERFACES:
2769 case NECP_POLICY_CONDITION_ENTITLEMENT:
2770 case NECP_POLICY_CONDITION_HAS_CLIENT:
2771 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
2772 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2773 validated = TRUE;
2774 }
2775 break;
2776 }
2777 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2778 if (condition_length == 0 || condition_length >= sizeof(u_int8_t)) {
2779 validated = TRUE;
2780 }
2781 break;
2782 }
2783 case NECP_POLICY_CONDITION_SDK_VERSION: {
2784 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2785 condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2786 validated = TRUE;
2787 }
2788 break;
2789 }
2790 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2791 if (condition_length >= sizeof(u_int16_t)) {
2792 validated = TRUE;
2793 }
2794 break;
2795 }
2796 case NECP_POLICY_CONDITION_PID: {
2797 if (condition_length >= sizeof(pid_t) &&
2798 condition_value != NULL) {
2799 validated = TRUE;
2800 }
2801 break;
2802 }
2803 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2804 if (condition_length >= sizeof(u_int32_t)) {
2805 validated = TRUE;
2806 }
2807 break;
2808 }
2809 case NECP_POLICY_CONDITION_UID:
2810 case NECP_POLICY_CONDITION_REAL_UID: {
2811 if (condition_length >= sizeof(uid_t)) {
2812 validated = TRUE;
2813 }
2814 break;
2815 }
2816 case NECP_POLICY_CONDITION_LOCAL_ADDR:
2817 case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2818 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2819 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2820 validated = TRUE;
2821 }
2822 break;
2823 }
2824 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2825 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2826 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2827 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2828 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2829 validated = TRUE;
2830 }
2831 break;
2832 }
2833 case NECP_POLICY_CONDITION_AGENT_TYPE: {
2834 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2835 condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2836 validated = TRUE;
2837 }
2838 break;
2839 }
2840 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2841 if (condition_length >= sizeof(u_int16_t)) {
2842 validated = TRUE;
2843 }
2844 break;
2845 }
2846 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2847 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2848 if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2849 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2850 validated = TRUE;
2851 }
2852 break;
2853 }
2854 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2855 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2856 if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2857 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2858 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2859 validated = TRUE;
2860 }
2861 break;
2862 }
2863 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2864 if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2865 validated = TRUE;
2866 }
2867 break;
2868 }
2869 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2870 validated = TRUE;
2871 break;
2872 }
2873 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2874 validated = TRUE;
2875 break;
2876 }
2877 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2878 if (condition_length >= sizeof(u_int16_t)) {
2879 u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2880 if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2881 validated = TRUE;
2882 }
2883 }
2884 break;
2885 }
2886 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2887 validated = TRUE;
2888 break;
2889 }
2890 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
2891 validated = TRUE;
2892 break;
2893 }
2894 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2895 validated = TRUE;
2896 break;
2897 }
2898 case NECP_POLICY_CONDITION_SCHEME_PORT: {
2899 if (condition_length >= sizeof(u_int16_t)) {
2900 validated = TRUE;
2901 }
2902 break;
2903 }
2904 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2905 if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2906 validated = TRUE;
2907 }
2908 break;
2909 }
2910 default: {
2911 validated = FALSE;
2912 break;
2913 }
2914 }
2915
2916 if (necp_debug) {
2917 NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2918 }
2919
2920 return validated;
2921 }
2922
2923 static bool
necp_policy_route_rule_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2924 necp_policy_route_rule_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2925 {
2926 return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2927 necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2928 }
2929
2930 static bool
necp_policy_route_rule_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2931 necp_policy_route_rule_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2932 {
2933 bool validated = FALSE;
2934 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2935 switch (type) {
2936 case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2937 validated = TRUE;
2938 break;
2939 }
2940 case NECP_ROUTE_RULE_DENY_INTERFACE: {
2941 validated = TRUE;
2942 break;
2943 }
2944 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2945 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2946 validated = (rule_length >= sizeof(u_int32_t));
2947 break;
2948 }
2949 case NECP_ROUTE_RULE_QOS_MARKING: {
2950 validated = TRUE;
2951 break;
2952 }
2953 case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2954 validated = TRUE;
2955 break;
2956 }
2957 case NECP_ROUTE_RULE_USE_NETAGENT:
2958 case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2959 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2960 validated = (rule_length >= sizeof(uuid_t));
2961 break;
2962 }
2963 case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2964 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2965 validated = (rule_length >= sizeof(uint32_t));
2966 break;
2967 }
2968 default: {
2969 validated = FALSE;
2970 break;
2971 }
2972 }
2973
2974 if (necp_debug) {
2975 NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2976 }
2977
2978 return validated;
2979 }
2980
2981 static int
necp_get_posix_error_for_necp_error(int response_error)2982 necp_get_posix_error_for_necp_error(int response_error)
2983 {
2984 switch (response_error) {
2985 case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2986 case NECP_ERROR_INVALID_TLV:
2987 case NECP_ERROR_POLICY_RESULT_INVALID:
2988 case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2989 case NECP_ERROR_ROUTE_RULES_INVALID: {
2990 return EINVAL;
2991 }
2992 case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2993 return ENOENT;
2994 }
2995 case NECP_ERROR_INVALID_PROCESS: {
2996 return EPERM;
2997 }
2998 case NECP_ERROR_INTERNAL:
2999 default: {
3000 return ENOMEM;
3001 }
3002 }
3003 }
3004
3005 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)3006 necp_handle_policy_add(struct necp_session *session,
3007 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
3008 {
3009 bool has_default_condition = FALSE;
3010 bool has_non_default_condition = FALSE;
3011 bool has_application_condition = FALSE;
3012 bool has_real_application_condition = FALSE;
3013 bool requires_application_condition = FALSE;
3014 bool has_kernel_pid = FALSE;
3015 bool is_pass_skip = FALSE;
3016 u_int32_t conditions_array_size = 0;
3017 u_int8_t *conditions_array = NULL;
3018 int conditions_array_cursor;
3019
3020 bool has_default_route_rule = FALSE;
3021 u_int32_t route_rules_array_size = 0;
3022 u_int8_t *route_rules_array = NULL;
3023 int route_rules_array_cursor;
3024
3025 int cursor;
3026 int error = 0;
3027 u_int32_t response_error = NECP_ERROR_INTERNAL;
3028
3029 necp_policy_order order = 0;
3030 struct necp_session_policy *policy = NULL;
3031 u_int32_t policy_result_size = 0;
3032 u_int8_t *policy_result = NULL;
3033
3034 // Read policy order
3035 error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
3036 if (error) {
3037 NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
3038 response_error = NECP_ERROR_INVALID_TLV;
3039 goto fail;
3040 }
3041
3042 // Read policy result
3043 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
3044 if (error || cursor < 0) {
3045 NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
3046 response_error = NECP_ERROR_INVALID_TLV;
3047 goto fail;
3048 }
3049
3050 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
3051 if (error || policy_result_size == 0) {
3052 NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
3053 response_error = NECP_ERROR_INVALID_TLV;
3054 goto fail;
3055 }
3056 if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
3057 NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
3058 response_error = NECP_ERROR_INVALID_TLV;
3059 goto fail;
3060 }
3061 policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
3062 if (policy_result == NULL) {
3063 NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
3064 response_error = NECP_ERROR_INTERNAL;
3065 goto fail;
3066 }
3067 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
3068 if (error) {
3069 NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
3070 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3071 goto fail;
3072 }
3073 if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
3074 NECPLOG0(LOG_ERR, "Failed to validate policy result");
3075 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3076 goto fail;
3077 }
3078
3079 if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
3080 // Read route rules conditions
3081
3082 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3083 cursor >= 0;
3084 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3085 u_int32_t route_rule_size = 0;
3086 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3087 if (os_add_overflow(route_rules_array_size,
3088 (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
3089 &route_rules_array_size)) {
3090 NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
3091 response_error = NECP_ERROR_INVALID_TLV;
3092 goto fail;
3093 }
3094 }
3095
3096 if (route_rules_array_size == 0) {
3097 NECPLOG0(LOG_ERR, "Failed to get policy route rules");
3098 response_error = NECP_ERROR_INVALID_TLV;
3099 goto fail;
3100 }
3101 if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
3102 NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
3103 response_error = NECP_ERROR_INVALID_TLV;
3104 goto fail;
3105 }
3106 route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
3107 if (route_rules_array == NULL) {
3108 NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
3109 response_error = NECP_ERROR_INTERNAL;
3110 goto fail;
3111 }
3112
3113 route_rules_array_cursor = 0;
3114 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3115 cursor >= 0;
3116 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3117 u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
3118 u_int32_t route_rule_size = 0;
3119 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3120 if (route_rule_size > 0 &&
3121 (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
3122 // Add type
3123 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
3124 route_rules_array_cursor += sizeof(route_rule_type);
3125
3126 // Add length
3127 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
3128 route_rules_array_cursor += sizeof(route_rule_size);
3129
3130 // Add value
3131 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
3132
3133 if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3134 NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
3135 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3136 goto fail;
3137 }
3138
3139 if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3140 if (has_default_route_rule) {
3141 NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
3142 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3143 goto fail;
3144 }
3145 has_default_route_rule = TRUE;
3146 }
3147
3148 route_rules_array_cursor += route_rule_size;
3149 }
3150 }
3151 }
3152
3153 // Read policy conditions
3154 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3155 cursor >= 0;
3156 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3157 u_int32_t condition_size = 0;
3158 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3159
3160 if (condition_size > 0) {
3161 if (os_add_overflow(conditions_array_size,
3162 (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
3163 &conditions_array_size)) {
3164 NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
3165 response_error = NECP_ERROR_INVALID_TLV;
3166 goto fail;
3167 }
3168 }
3169 }
3170
3171 if (conditions_array_size == 0) {
3172 NECPLOG0(LOG_ERR, "Failed to get policy conditions");
3173 response_error = NECP_ERROR_INVALID_TLV;
3174 goto fail;
3175 }
3176 if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
3177 NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
3178 response_error = NECP_ERROR_INVALID_TLV;
3179 goto fail;
3180 }
3181 conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
3182 if (conditions_array == NULL) {
3183 NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
3184 response_error = NECP_ERROR_INTERNAL;
3185 goto fail;
3186 }
3187
3188 conditions_array_cursor = 0;
3189 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3190 cursor >= 0;
3191 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3192 u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
3193 u_int32_t condition_size = 0;
3194 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3195 if (condition_size > 0 &&
3196 (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
3197 // Add type
3198 memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
3199 conditions_array_cursor += sizeof(condition_type);
3200
3201 // Add length
3202 memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
3203 conditions_array_cursor += sizeof(condition_size);
3204
3205 // Add value
3206 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
3207 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))) {
3208 NECPLOG0(LOG_ERR, "Failed to validate policy condition");
3209 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3210 goto fail;
3211 }
3212
3213 if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
3214 has_default_condition = TRUE;
3215 } else {
3216 has_non_default_condition = TRUE;
3217 }
3218 if (has_default_condition && has_non_default_condition) {
3219 NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
3220 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3221 goto fail;
3222 }
3223
3224 if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
3225 has_application_condition = TRUE;
3226 }
3227
3228 if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
3229 has_real_application_condition = TRUE;
3230 }
3231
3232 if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
3233 requires_application_condition = TRUE;
3234 }
3235
3236 if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
3237 has_kernel_pid = TRUE;
3238 }
3239
3240 conditions_array_cursor += condition_size;
3241 }
3242 }
3243
3244 if (requires_application_condition && !has_application_condition) {
3245 NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
3246 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3247 goto fail;
3248 }
3249
3250 if (has_kernel_pid && !is_pass_skip) {
3251 NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
3252 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3253 goto fail;
3254 }
3255
3256 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) {
3257 response_error = NECP_ERROR_INTERNAL;
3258 goto fail;
3259 }
3260
3261 return policy->local_id;
3262
3263 fail:
3264 if (policy_result != NULL) {
3265 kfree_data_sized_by(policy_result, policy_result_size);
3266 }
3267 if (conditions_array != NULL) {
3268 kfree_data_sized_by(conditions_array, conditions_array_size);
3269 }
3270 if (route_rules_array != NULL) {
3271 kfree_data_sized_by(route_rules_array, route_rules_array_size);
3272 }
3273
3274 if (return_error != NULL) {
3275 *return_error = necp_get_posix_error_for_necp_error(response_error);
3276 }
3277 return 0;
3278 }
3279
3280 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)3281 necp_policy_get_new_id(struct necp_session *session)
3282 {
3283 session->last_policy_id++;
3284 if (session->last_policy_id < 1) {
3285 session->last_policy_id = 1;
3286 }
3287
3288 necp_policy_id newid = session->last_policy_id;
3289
3290 if (newid == 0) {
3291 NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
3292 return 0;
3293 }
3294
3295 return newid;
3296 }
3297
3298 /*
3299 * For the policy dump response this is the structure:
3300 *
3301 * <NECP_PACKET_HEADER>
3302 * {
3303 * type : NECP_TLV_POLICY_DUMP
3304 * length : ...
3305 * value :
3306 * {
3307 * {
3308 * type : NECP_TLV_POLICY_ID
3309 * len : ...
3310 * value : ...
3311 * }
3312 * {
3313 * type : NECP_TLV_POLICY_ORDER
3314 * len : ...
3315 * value : ...
3316 * }
3317 * {
3318 * type : NECP_TLV_POLICY_RESULT_STRING
3319 * len : ...
3320 * value : ...
3321 * }
3322 * {
3323 * type : NECP_TLV_POLICY_OWNER
3324 * len : ...
3325 * value : ...
3326 * }
3327 * {
3328 * type : NECP_TLV_POLICY_CONDITION
3329 * len : ...
3330 * value :
3331 * {
3332 * {
3333 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3334 * len : ...
3335 * value : ...
3336 * }
3337 * {
3338 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3339 * len : ...
3340 * value : ...
3341 * }
3342 * ...
3343 * }
3344 * }
3345 * }
3346 * }
3347 * {
3348 * type : NECP_TLV_POLICY_DUMP
3349 * length : ...
3350 * value :
3351 * {
3352 * {
3353 * type : NECP_TLV_POLICY_ID
3354 * len : ...
3355 * value : ...
3356 * }
3357 * {
3358 * type : NECP_TLV_POLICY_ORDER
3359 * len : ...
3360 * value : ...
3361 * }
3362 * {
3363 * type : NECP_TLV_POLICY_RESULT_STRING
3364 * len : ...
3365 * value : ...
3366 * }
3367 * {
3368 * type : NECP_TLV_POLICY_OWNER
3369 * len : ...
3370 * value : ...
3371 * }
3372 * {
3373 * type : NECP_TLV_POLICY_CONDITION
3374 * len : ...
3375 * value :
3376 * {
3377 * {
3378 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3379 * len : ...
3380 * value : ...
3381 * }
3382 * {
3383 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3384 * len : ...
3385 * value : ...
3386 * }
3387 * ...
3388 * }
3389 * }
3390 * }
3391 * }
3392 * ...
3393 */
3394 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3395 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3396 {
3397 struct necp_kernel_socket_policy * __single policy = NULL;
3398 int policy_i;
3399 int policy_count = 0;
3400 u_int8_t * __indexable * __indexable tlv_buffer_pointers = NULL;
3401 u_int32_t * __indexable tlv_buffer_lengths = NULL;
3402 u_int32_t total_tlv_len = 0;
3403 u_int8_t * __indexable result_buf = NULL;
3404 u_int8_t *result_buf_cursor = result_buf;
3405 char result_string[MAX_RESULT_STRING_LEN];
3406 char proc_name_string[MAXCOMLEN + 1];
3407
3408 int error_code = 0;
3409 bool error_occured = false;
3410 u_int32_t response_error = NECP_ERROR_INTERNAL;
3411
3412 #define REPORT_ERROR(error) error_occured = true; \
3413 response_error = error; \
3414 goto done
3415
3416 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
3417 REPORT_ERROR(error)
3418
3419 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3420 if (cred_result != 0) {
3421 NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3422 REPORT_ERROR(NECP_ERROR_INTERNAL);
3423 }
3424
3425 // LOCK
3426 lck_rw_lock_shared(&necp_kernel_policy_lock);
3427
3428 if (necp_debug) {
3429 NECPLOG0(LOG_DEBUG, "Gathering policies");
3430 }
3431
3432 policy_count = necp_kernel_application_policies_count;
3433
3434 tlv_buffer_pointers = kalloc_type(u_int8_t * __indexable, policy_count, M_WAITOK | Z_ZERO);
3435 if (tlv_buffer_pointers == NULL) {
3436 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3437 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3438 }
3439
3440 tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3441 if (tlv_buffer_lengths == NULL) {
3442 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3443 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3444 }
3445
3446 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3447 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3448
3449 memset(result_string, 0, MAX_RESULT_STRING_LEN);
3450 memset(proc_name_string, 0, MAXCOMLEN + 1);
3451
3452 necp_get_result_description(result_string, policy->result, policy->result_parameter);
3453 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3454
3455 u_int16_t proc_name_len = strbuflen(proc_name_string, sizeof(proc_name_string) - 1) + 1;
3456 u_int16_t result_string_len = strbuflen(result_string, sizeof(result_string) - 1) + 1;
3457
3458 if (necp_debug) {
3459 NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3460 }
3461
3462 u_int32_t total_allocated_bytes = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) + // NECP_TLV_POLICY_ID
3463 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) + // NECP_TLV_POLICY_ORDER
3464 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) + // NECP_TLV_POLICY_SESSION_ORDER
3465 sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len + // NECP_TLV_POLICY_RESULT_STRING
3466 sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len + // NECP_TLV_POLICY_OWNER
3467 sizeof(u_int8_t) + sizeof(u_int32_t); // NECP_TLV_POLICY_CONDITION
3468
3469 // We now traverse the condition_mask to see how much space we need to allocate
3470 u_int64_t condition_mask = policy->condition_mask;
3471 u_int64_t condition_negated_mask = policy->condition_negated_mask;
3472 u_int8_t num_conditions = 0;
3473 struct necp_string_id_mapping *account_id_entry = NULL;
3474 char if_name[IFXNAMSIZ];
3475 u_int32_t condition_tlv_length = 0;
3476 memset(if_name, 0, sizeof(if_name));
3477
3478 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3479 num_conditions++;
3480 } else {
3481 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3482 num_conditions++;
3483 }
3484 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3485 num_conditions++;
3486 }
3487 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3488 snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3489 condition_tlv_length += strbuflen(if_name, sizeof(if_name) - 1) + 1;
3490 num_conditions++;
3491 }
3492 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3493 condition_tlv_length += sizeof(policy->cond_protocol);
3494 num_conditions++;
3495 }
3496 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3497 condition_tlv_length += sizeof(uuid_t);
3498 num_conditions++;
3499 }
3500 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3501 condition_tlv_length += sizeof(uuid_t);
3502 num_conditions++;
3503 }
3504 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3505 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3506 u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3507 condition_tlv_length += domain_len;
3508 num_conditions++;
3509 }
3510 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3511 condition_tlv_length += sizeof(u_int32_t);
3512 num_conditions++;
3513 }
3514 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3515 u_int32_t url_len = strlen(policy->cond_url) + 1;
3516 condition_tlv_length += url_len;
3517 num_conditions++;
3518 }
3519 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3520 account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3521 u_int32_t account_id_len = 0;
3522 if (account_id_entry) {
3523 account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3524 }
3525 condition_tlv_length += account_id_len;
3526 num_conditions++;
3527 }
3528 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3529 condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3530 num_conditions++;
3531 }
3532 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3533 condition_tlv_length += sizeof(uid_t);
3534 num_conditions++;
3535 }
3536 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3537 condition_tlv_length += sizeof(uid_t);
3538 num_conditions++;
3539 }
3540 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3541 condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3542 num_conditions++;
3543 }
3544 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3545 num_conditions++;
3546 }
3547 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3548 u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3549 condition_tlv_length += entitlement_len;
3550 num_conditions++;
3551 }
3552 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3553 num_conditions++;
3554 }
3555 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3556 num_conditions++;
3557 }
3558 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3559 condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3560 num_conditions++;
3561 }
3562 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3563 condition_tlv_length += sizeof(policy->cond_local_networks_flags);
3564 num_conditions++;
3565 }
3566 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3567 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3568 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3569 } else {
3570 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3571 }
3572 num_conditions++;
3573 }
3574 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3575 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3576 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3577 } else {
3578 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3579 }
3580 num_conditions++;
3581 }
3582 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3583 condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3584 num_conditions++;
3585 }
3586 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3587 condition_tlv_length += sizeof(u_int32_t);
3588 num_conditions++;
3589 }
3590 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3591 num_conditions++;
3592 }
3593 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3594 num_conditions++;
3595 }
3596 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3597 u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3598 condition_tlv_length += identifier_len;
3599 num_conditions++;
3600 }
3601 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3602 condition_tlv_length += sizeof(u_int16_t);
3603 num_conditions++;
3604 }
3605 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3606 num_conditions++;
3607 }
3608 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3609 num_conditions++;
3610 }
3611 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3612 condition_tlv_length += sizeof(u_int16_t);
3613 num_conditions++;
3614 }
3615 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3616 condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3617 num_conditions++;
3618 }
3619 }
3620
3621 // These are for the condition TLVs (id, length, flags). The space for "value" is already accounted for above.
3622 condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int8_t));
3623 total_allocated_bytes += condition_tlv_length;
3624
3625 u_int8_t * __indexable tlv_buffer;
3626 tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3627 if (tlv_buffer == NULL) {
3628 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3629 continue;
3630 }
3631
3632 u_int8_t *cursor = tlv_buffer;
3633 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3634 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3635 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3636 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3637 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3638
3639 #define N_QUICK 256
3640 u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3641
3642 u_int8_t * __indexable cond_buf; // To be used for condition TLVs
3643 if (condition_tlv_length <= N_QUICK) {
3644 cond_buf = q_cond_buf;
3645 } else {
3646 cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3647 if (cond_buf == NULL) {
3648 NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3649 kfree_data(tlv_buffer, total_allocated_bytes);
3650 continue;
3651 }
3652 }
3653
3654 memset(cond_buf, 0, condition_tlv_length);
3655 u_int8_t *cond_buf_cursor = cond_buf;
3656 u_int8_t cond_flags = 0;
3657 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3658 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3659 } else {
3660 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3661 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3662 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);
3663 }
3664 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3665 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3666 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);
3667 }
3668 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3669 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3670 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);
3671 }
3672 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3673 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3674 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,
3675 if_name, cond_buf, condition_tlv_length);
3676 }
3677 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3678 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3679 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,
3680 cond_buf, condition_tlv_length);
3681 }
3682 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3683 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3684 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3685 if (entry != NULL) {
3686 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3687 cond_buf, condition_tlv_length);
3688 }
3689 }
3690 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3691 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3692 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3693 if (entry != NULL) {
3694 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3695 cond_buf, condition_tlv_length);
3696 }
3697 }
3698 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3699 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3700 cond_flags = ((condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) || (condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3701 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);
3702 }
3703 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3704 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3705 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,
3706 cond_buf, condition_tlv_length);
3707 }
3708 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3709 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_URL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3710 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);
3711 }
3712 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3713 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3714 if (account_id_entry != NULL) {
3715 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);
3716 }
3717 }
3718 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3719 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3720 uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3721 memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3722 memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3723 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PID, cond_flags, sizeof(pid_buffer), &pid_buffer,
3724 cond_buf, condition_tlv_length);
3725 }
3726 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3727 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3728 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,
3729 cond_buf, condition_tlv_length);
3730 }
3731 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3732 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3733 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,
3734 cond_buf, condition_tlv_length);
3735 }
3736 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3737 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3738 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,
3739 cond_buf, condition_tlv_length);
3740 }
3741 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3742 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3743 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, 0, "",
3744 cond_buf, condition_tlv_length);
3745 }
3746 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3747 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3748 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);
3749 }
3750 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3751 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3752 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);
3753 }
3754 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3755 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3756 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);
3757 }
3758 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3759 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SDK_VERSION) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3760 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION, cond_flags,
3761 sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3762 cond_buf, condition_tlv_length);
3763 }
3764 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3765 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3766 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3767 struct necp_policy_condition_addr_range range;
3768 memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3769 memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3770 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, cond_flags, sizeof(range), &range,
3771 cond_buf, condition_tlv_length);
3772 } else {
3773 struct necp_policy_condition_addr addr;
3774 addr.prefix = policy->cond_local_prefix;
3775 memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3776 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, cond_flags, sizeof(addr), &addr,
3777 cond_buf, condition_tlv_length);
3778 }
3779 }
3780 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3781 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3782 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3783 struct necp_policy_condition_addr_range range;
3784 memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3785 memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3786 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, cond_flags, sizeof(range), &range,
3787 cond_buf, condition_tlv_length);
3788 } else {
3789 struct necp_policy_condition_addr addr;
3790 addr.prefix = policy->cond_remote_prefix;
3791 memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3792 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, cond_flags, sizeof(addr), &addr,
3793 cond_buf, condition_tlv_length);
3794 }
3795 }
3796 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3797 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3798 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE, cond_flags,
3799 sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3800 cond_buf, condition_tlv_length);
3801 }
3802 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3803 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3804 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);
3805 }
3806 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3807 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3808 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);
3809 }
3810 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3811 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3812 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);
3813 }
3814 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3815 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3816 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);
3817 }
3818 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3819 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3820 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);
3821 }
3822 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3823 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3824 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);
3825 }
3826 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3827 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3828 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);
3829 }
3830 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3831 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3832 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);
3833 }
3834 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3835 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3836 uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3837 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3838 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3839 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3840 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, cond_flags, sizeof(flags), &flags,
3841 cond_buf, condition_tlv_length);
3842 }
3843 }
3844
3845 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3846 if (cond_buf != q_cond_buf) {
3847 kfree_data(cond_buf, condition_tlv_length);
3848 }
3849
3850 tlv_buffer_pointers[policy_i] = tlv_buffer;
3851 tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3852
3853 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
3854 total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3855 }
3856
3857 // UNLOCK
3858 lck_rw_done(&necp_kernel_policy_lock);
3859
3860 // Copy out
3861 if (out_buffer != 0) {
3862 if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3863 NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3864 REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3865 }
3866
3867 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3868 result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3869 if (result_buf == NULL) {
3870 NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3871 REPORT_ERROR(NECP_ERROR_INTERNAL);
3872 }
3873
3874 // Add four bytes for total length at the start
3875 memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3876
3877 // Copy the TLVs
3878 result_buf_cursor = result_buf + sizeof(u_int32_t);
3879 for (int i = 0; i < policy_count; i++) {
3880 if (tlv_buffer_pointers[i] != NULL) {
3881 result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3882 result_buf, total_tlv_len + sizeof(u_int32_t));
3883 }
3884 }
3885
3886 int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3887 if (copy_error) {
3888 NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3889 REPORT_ERROR(NECP_ERROR_INTERNAL);
3890 }
3891 }
3892
3893 done:
3894
3895 if (error_occured) {
3896 error_code = necp_get_posix_error_for_necp_error(response_error);
3897 }
3898
3899 if (result_buf != NULL) {
3900 kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3901 }
3902
3903 if (tlv_buffer_pointers != NULL) {
3904 for (int i = 0; i < policy_count; i++) {
3905 if (tlv_buffer_pointers[i] != NULL) {
3906 kfree_data_addr(tlv_buffer_pointers[i]);
3907 tlv_buffer_pointers[i] = NULL;
3908 }
3909 }
3910 kfree_type(u_int8_t * __indexable, policy_count, tlv_buffer_pointers);
3911 }
3912
3913 if (tlv_buffer_lengths != NULL) {
3914 kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3915 }
3916 #undef N_QUICK
3917 #undef RESET_COND_BUF
3918 #undef REPORT_ERROR
3919 #undef UNLOCK_AND_REPORT_ERROR
3920
3921 return error_code;
3922 }
3923
3924 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)3925 necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t * __sized_by(conditions_array_size)conditions_array, u_int32_t conditions_array_size, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, u_int8_t *__sized_by(result_size)result, u_int32_t result_size)
3926 {
3927 struct necp_session_policy *new_policy = NULL;
3928 struct necp_session_policy *tmp_policy = NULL;
3929
3930 if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3931 goto done;
3932 }
3933
3934 new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3935 new_policy->applied = FALSE;
3936 new_policy->pending_deletion = FALSE;
3937 new_policy->pending_update = FALSE;
3938 new_policy->order = order;
3939 new_policy->conditions = conditions_array;
3940 new_policy->conditions_size = conditions_array_size;
3941 new_policy->route_rules = route_rules_array;
3942 new_policy->route_rules_size = route_rules_array_size;
3943 new_policy->result = result;
3944 new_policy->result_size = result_size;
3945 new_policy->local_id = necp_policy_get_new_id(session);
3946
3947 LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3948
3949 session->dirty = TRUE;
3950
3951 if (necp_debug) {
3952 NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3953 }
3954 done:
3955 return new_policy;
3956 }
3957
3958 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3959 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3960 {
3961 struct necp_session_policy *policy = NULL;
3962 if (policy_id == 0) {
3963 return NULL;
3964 }
3965
3966 LIST_FOREACH(policy, &session->policies, chain) {
3967 if (policy->local_id == policy_id) {
3968 return policy;
3969 }
3970 }
3971
3972 return NULL;
3973 }
3974
3975 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3976 necp_policy_get_result_type(struct necp_session_policy *policy)
3977 {
3978 return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3979 }
3980
3981 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3982 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3983 {
3984 return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3985 }
3986
3987 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)3988 necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t * __sized_by(parameter_buffer_length)parameter_buffer, u_int32_t parameter_buffer_length)
3989 {
3990 if (policy) {
3991 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3992 if (parameter_buffer_length >= parameter_length) {
3993 u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3994 if (parameter && parameter_buffer) {
3995 memcpy(parameter_buffer, parameter, parameter_length);
3996 return TRUE;
3997 }
3998 }
3999 }
4000
4001 return FALSE;
4002 }
4003
4004 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)4005 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
4006 {
4007 if (session == NULL || policy == NULL) {
4008 return FALSE;
4009 }
4010
4011 policy->pending_deletion = TRUE;
4012 session->dirty = TRUE;
4013
4014 if (necp_debug) {
4015 NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
4016 }
4017 return TRUE;
4018 }
4019
4020 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)4021 necp_policy_mark_all_for_deletion(struct necp_session *session)
4022 {
4023 struct necp_session_policy *policy = NULL;
4024 struct necp_session_policy *temp_policy = NULL;
4025
4026 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4027 necp_policy_mark_for_deletion(session, policy);
4028 }
4029
4030 return TRUE;
4031 }
4032
4033 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)4034 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
4035 {
4036 if (session == NULL || policy == NULL) {
4037 return FALSE;
4038 }
4039
4040 LIST_REMOVE(policy, chain);
4041
4042 if (policy->result) {
4043 kfree_data_sized_by(policy->result, policy->result_size);
4044 policy->result = NULL;
4045 policy->result_size = 0;
4046 }
4047
4048 if (policy->conditions) {
4049 kfree_data_sized_by(policy->conditions, policy->conditions_size);
4050 policy->conditions = NULL;
4051 policy->conditions_size = 0;
4052 }
4053
4054 if (policy->route_rules) {
4055 kfree_data_sized_by(policy->route_rules, policy->route_rules_size);
4056 policy->route_rules = NULL;
4057 policy->route_rules_size = 0;
4058 }
4059
4060 zfree(necp_session_policy_zone, policy);
4061
4062 if (necp_debug) {
4063 NECPLOG0(LOG_DEBUG, "Removed NECP policy");
4064 }
4065 return TRUE;
4066 }
4067
4068 static bool
necp_policy_unapply(struct necp_session_policy * policy)4069 necp_policy_unapply(struct necp_session_policy *policy)
4070 {
4071 int i = 0;
4072 if (policy == NULL) {
4073 return FALSE;
4074 }
4075
4076 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4077
4078 // Release local uuid mappings
4079 if (!uuid_is_null(policy->applied_app_uuid)) {
4080 bool removed_mapping = FALSE;
4081 if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
4082 necp_uuid_app_id_mappings_dirty = TRUE;
4083 necp_num_uuid_app_id_mappings--;
4084 }
4085 uuid_clear(policy->applied_app_uuid);
4086 }
4087 if (!uuid_is_null(policy->applied_real_app_uuid)) {
4088 necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
4089 uuid_clear(policy->applied_real_app_uuid);
4090 }
4091 if (!uuid_is_null(policy->applied_result_uuid)) {
4092 necp_remove_uuid_service_id_mapping(policy->applied_result_uuid);
4093 uuid_clear(policy->applied_result_uuid);
4094 }
4095
4096 // Release string mappings
4097 if (policy->applied_account != NULL) {
4098 necp_remove_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(policy->applied_account));
4099 kfree_data_sized_by(policy->applied_account, policy->applied_account_size);
4100 policy->applied_account = NULL;
4101 policy->applied_account_size = 0;
4102 }
4103
4104 // Release route rule
4105 if (policy->applied_route_rules_id != 0) {
4106 necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
4107 policy->applied_route_rules_id = 0;
4108 }
4109
4110 // Remove socket policies
4111 for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
4112 if (policy->kernel_socket_policies[i] != 0) {
4113 necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
4114 policy->kernel_socket_policies[i] = 0;
4115 }
4116 }
4117
4118 // Remove IP output policies
4119 for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
4120 if (policy->kernel_ip_output_policies[i] != 0) {
4121 necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
4122 policy->kernel_ip_output_policies[i] = 0;
4123 }
4124 }
4125
4126 policy->applied = FALSE;
4127
4128 return TRUE;
4129 }
4130
4131 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
4132 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
4133 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
4134 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
4135 struct necp_policy_result_ip_tunnel {
4136 u_int32_t secondary_result;
4137 char interface_name[IFXNAMSIZ];
4138 } __attribute__((__packed__));
4139
4140 struct necp_policy_result_service {
4141 uuid_t identifier;
4142 u_int32_t data;
4143 } __attribute__((__packed__));
4144
4145 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy)4146 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
4147 {
4148 bool socket_only_conditions = FALSE;
4149 bool socket_ip_conditions = FALSE;
4150
4151 bool socket_layer_non_id_conditions = FALSE;
4152 bool ip_output_layer_non_id_conditions = FALSE;
4153 bool ip_output_layer_non_id_only = FALSE;
4154 bool ip_output_layer_id_condition = FALSE;
4155 bool ip_output_layer_tunnel_condition_from_id = FALSE;
4156 bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
4157 necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
4158
4159 u_int64_t master_condition_mask = 0;
4160 u_int64_t master_condition_negated_mask = 0;
4161 ifnet_t __single cond_bound_interface = NULL;
4162 u_int32_t cond_account_id = 0;
4163 char *cond_domain __null_terminated = NULL;
4164 u_int32_t cond_domain_filter = 0;
4165 char *cond_url __null_terminated = NULL;
4166 char *cond_custom_entitlement __null_terminated = NULL;
4167 char *cond_signing_identifier __null_terminated = NULL;
4168 pid_t cond_pid = 0;
4169 int32_t cond_pid_version = 0;
4170 uid_t cond_uid = 0;
4171 uid_t cond_real_uid = 0;
4172 necp_app_id cond_app_id = 0;
4173 necp_app_id cond_real_app_id = 0;
4174 struct necp_policy_condition_tc_range cond_traffic_class;
4175 cond_traffic_class.start_tc = 0;
4176 cond_traffic_class.end_tc = 0;
4177 u_int16_t cond_protocol = 0;
4178 union necp_sockaddr_union cond_local_start;
4179 union necp_sockaddr_union cond_local_end;
4180 u_int8_t cond_local_prefix = 0;
4181 union necp_sockaddr_union cond_remote_start;
4182 union necp_sockaddr_union cond_remote_end;
4183 u_int8_t cond_remote_prefix = 0;
4184 u_int32_t cond_client_flags = 0;
4185 u_int8_t cond_local_networks_flags = 0;
4186 u_int32_t offset = 0;
4187 u_int8_t ultimate_result = 0;
4188 u_int32_t secondary_result = 0;
4189 struct necp_policy_condition_agent_type cond_agent_type = {};
4190 struct necp_policy_condition_sdk_version cond_sdk_version = {};
4191 u_int16_t cond_packet_filter_tags = 0;
4192 u_int16_t cond_scheme_port = 0;
4193 u_int32_t cond_bound_interface_flags = 0;
4194 u_int32_t cond_bound_interface_eflags = 0;
4195 u_int32_t cond_bound_interface_xflags = 0;
4196 necp_kernel_policy_result_parameter secondary_result_parameter;
4197 memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
4198 u_int32_t cond_last_interface_index = 0;
4199 necp_kernel_policy_result_parameter ultimate_result_parameter;
4200 memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
4201
4202 if (policy == NULL) {
4203 return FALSE;
4204 }
4205
4206 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4207
4208 // Process conditions
4209 while (offset < policy->conditions_size) {
4210 u_int32_t length = 0;
4211 u_int8_t * __indexable value = necp_buffer_get_tlv_value(policy->conditions, policy->conditions_size, offset, &length);
4212
4213 u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
4214 u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
4215 bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
4216 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
4217 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
4218 switch (condition_type) {
4219 case NECP_POLICY_CONDITION_DEFAULT: {
4220 socket_ip_conditions = TRUE;
4221 break;
4222 }
4223 case NECP_POLICY_CONDITION_ALL_INTERFACES: {
4224 master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
4225 socket_ip_conditions = TRUE;
4226 break;
4227 }
4228 case NECP_POLICY_CONDITION_HAS_CLIENT: {
4229 master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
4230 socket_only_conditions = TRUE;
4231 break;
4232 }
4233 case NECP_POLICY_CONDITION_ENTITLEMENT: {
4234 if (condition_length > 0) {
4235 if (cond_custom_entitlement == NULL) {
4236 cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
4237 if (cond_custom_entitlement != NULL) {
4238 master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
4239 socket_only_conditions = TRUE;
4240 }
4241 }
4242 } else {
4243 master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
4244 socket_only_conditions = TRUE;
4245 }
4246 break;
4247 }
4248 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
4249 master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4250 if (condition_is_negative) {
4251 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4252 }
4253 socket_only_conditions = TRUE;
4254 break;
4255 }
4256 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
4257 master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
4258 socket_only_conditions = TRUE;
4259 break;
4260 }
4261 case NECP_POLICY_CONDITION_SDK_VERSION: {
4262 if (condition_length >= sizeof(cond_sdk_version)) {
4263 master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
4264 memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
4265 socket_only_conditions = TRUE;
4266 }
4267 break;
4268 }
4269 case NECP_POLICY_CONDITION_DOMAIN: {
4270 // Make sure there is only one such rule
4271 if (condition_length > 0 && cond_domain == NULL) {
4272 const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
4273
4274 u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
4275 cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
4276 if (cond_domain != NULL) {
4277 master_condition_mask |= mask_value;
4278 if (condition_is_negative) {
4279 master_condition_negated_mask |= mask_value;
4280 }
4281 socket_only_conditions = TRUE;
4282 }
4283 }
4284 break;
4285 }
4286 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
4287 // Make sure there is only one such rule
4288 if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
4289 memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
4290 if (cond_domain_filter != 0) {
4291 master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4292 if (condition_is_negative) {
4293 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4294 }
4295 socket_only_conditions = TRUE;
4296 }
4297 }
4298 break;
4299 }
4300 case NECP_POLICY_CONDITION_URL: {
4301 // Make sure there is only one such rule
4302 if (condition_length > 0 && cond_url == NULL) {
4303 u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
4304 cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
4305 if (cond_url != NULL) {
4306 master_condition_mask |= mask_value;
4307 if (condition_is_negative) {
4308 master_condition_negated_mask |= mask_value;
4309 }
4310 socket_only_conditions = TRUE;
4311 }
4312 }
4313 break;
4314 }
4315 case NECP_POLICY_CONDITION_ACCOUNT: {
4316 // Make sure there is only one such rule
4317 if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
4318 size_t string_buffer_size = 0;
4319 char * __sized_by(string_buffer_size) string = NULL;
4320 string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
4321 string_buffer_size = condition_length + 1;
4322 if (string != NULL) {
4323 memcpy(string, condition_value, condition_length);
4324 string[condition_length] = 0;
4325 cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(string, &string[condition_length]));
4326 if (cond_account_id != 0) {
4327 policy->applied_account = string; // Save the string in parent policy
4328 policy->applied_account_size = string_buffer_size;
4329 master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4330 if (condition_is_negative) {
4331 master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4332 }
4333 socket_only_conditions = TRUE;
4334 } else {
4335 kfree_data_sized_by(string, string_buffer_size);
4336 }
4337 }
4338 }
4339 break;
4340 }
4341 case NECP_POLICY_CONDITION_APPLICATION: {
4342 // Make sure there is only one such rule, because we save the uuid in the policy
4343 if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
4344 bool allocated_mapping = FALSE;
4345 uuid_t application_uuid;
4346 memcpy(application_uuid, condition_value, sizeof(uuid_t));
4347 cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
4348 if (cond_app_id != 0) {
4349 if (allocated_mapping) {
4350 necp_uuid_app_id_mappings_dirty = TRUE;
4351 necp_num_uuid_app_id_mappings++;
4352 }
4353 uuid_copy(policy->applied_app_uuid, application_uuid);
4354 master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
4355 if (condition_is_negative) {
4356 master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
4357 }
4358 socket_only_conditions = TRUE;
4359 }
4360 }
4361 break;
4362 }
4363 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
4364 // Make sure there is only one such rule, because we save the uuid in the policy
4365 if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
4366 uuid_t real_application_uuid;
4367 memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
4368 cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
4369 if (cond_real_app_id != 0) {
4370 uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
4371 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4372 if (condition_is_negative) {
4373 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4374 }
4375 socket_only_conditions = TRUE;
4376 }
4377 }
4378 break;
4379 }
4380 case NECP_POLICY_CONDITION_PID: {
4381 if (condition_length >= sizeof(pid_t)) {
4382 master_condition_mask |= NECP_KERNEL_CONDITION_PID;
4383 if (condition_is_negative) {
4384 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
4385 }
4386 memcpy(&cond_pid, condition_value, sizeof(cond_pid));
4387 if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
4388 memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
4389 }
4390 socket_only_conditions = TRUE;
4391 }
4392 break;
4393 }
4394 case NECP_POLICY_CONDITION_UID: {
4395 if (condition_length >= sizeof(uid_t)) {
4396 master_condition_mask |= NECP_KERNEL_CONDITION_UID;
4397 if (condition_is_negative) {
4398 master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
4399 }
4400 memcpy(&cond_uid, condition_value, sizeof(cond_uid));
4401 socket_only_conditions = TRUE;
4402 }
4403 break;
4404 }
4405 case NECP_POLICY_CONDITION_REAL_UID: {
4406 if (condition_length >= sizeof(uid_t)) {
4407 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4408 if (condition_is_negative) {
4409 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4410 }
4411 memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
4412 socket_only_conditions = TRUE;
4413 }
4414 break;
4415 }
4416 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
4417 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
4418 master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4419 if (condition_is_negative) {
4420 master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4421 }
4422 memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
4423 socket_only_conditions = TRUE;
4424 }
4425 break;
4426 }
4427 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4428 if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4429 char interface_name[IFXNAMSIZ];
4430 memcpy(interface_name, condition_value, condition_length);
4431 interface_name[condition_length - 1] = 0; // Make sure the string is NULL terminated
4432 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[condition_length - 1]), &cond_bound_interface) == 0) {
4433 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4434 if (condition_is_negative) {
4435 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4436 }
4437 }
4438 socket_ip_conditions = TRUE;
4439 }
4440 break;
4441 }
4442 case NECP_POLICY_CONDITION_IP_PROTOCOL:
4443 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4444 if (condition_length >= sizeof(u_int16_t)) {
4445 master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4446 if (condition_is_negative) {
4447 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4448 }
4449 memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4450 if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4451 socket_only_conditions = TRUE;
4452 } else {
4453 socket_ip_conditions = TRUE;
4454 }
4455 }
4456 break;
4457 }
4458 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4459 if (condition_is_negative) {
4460 master_condition_negated_mask |= NECP_POLICY_CONDITION_LOCAL_NETWORKS;
4461 }
4462 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4463 socket_ip_conditions = TRUE;
4464 if (condition_length >= sizeof(u_int8_t)) {
4465 memcpy(&cond_local_networks_flags, condition_value, sizeof(cond_local_networks_flags));
4466 }
4467 break;
4468 }
4469 case NECP_POLICY_CONDITION_LOCAL_ADDR:
4470 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4471 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4472 if (!necp_address_is_valid(&address_struct->address.sa)) {
4473 break;
4474 }
4475
4476 cond_local_prefix = address_struct->prefix;
4477 memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4478 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4479 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4480 if (condition_is_negative) {
4481 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4482 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4483 }
4484 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4485 socket_only_conditions = TRUE;
4486 } else {
4487 socket_ip_conditions = TRUE;
4488 }
4489 break;
4490 }
4491 case NECP_POLICY_CONDITION_REMOTE_ADDR:
4492 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4493 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4494 if (!necp_address_is_valid(&address_struct->address.sa)) {
4495 break;
4496 }
4497
4498 cond_remote_prefix = address_struct->prefix;
4499 memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4500 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4501 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4502 if (condition_is_negative) {
4503 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4504 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4505 }
4506 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4507 socket_only_conditions = TRUE;
4508 } else {
4509 socket_ip_conditions = TRUE;
4510 }
4511 break;
4512 }
4513 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4514 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4515 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4516 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4517 !necp_address_is_valid(&address_struct->end_address.sa)) {
4518 break;
4519 }
4520
4521 memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4522 memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4523 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4524 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4525 if (condition_is_negative) {
4526 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4527 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4528 }
4529 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4530 socket_only_conditions = TRUE;
4531 } else {
4532 socket_ip_conditions = TRUE;
4533 }
4534 break;
4535 }
4536 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4537 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4538 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4539 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4540 !necp_address_is_valid(&address_struct->end_address.sa)) {
4541 break;
4542 }
4543
4544 memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4545 memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4546 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4547 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4548 if (condition_is_negative) {
4549 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4550 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4551 }
4552 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4553 socket_only_conditions = TRUE;
4554 } else {
4555 socket_ip_conditions = TRUE;
4556 }
4557 break;
4558 }
4559 case NECP_POLICY_CONDITION_AGENT_TYPE: {
4560 if (condition_length >= sizeof(cond_agent_type)) {
4561 master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4562 memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4563 socket_only_conditions = TRUE;
4564 }
4565 break;
4566 }
4567 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4568 if (condition_is_negative) {
4569 master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4570 }
4571 master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4572 socket_only_conditions = TRUE;
4573 if (condition_length >= sizeof(u_int32_t)) {
4574 memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4575 } else {
4576 // Empty means match on fallback traffic
4577 cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4578 }
4579 break;
4580 }
4581 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4582 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4583 if (condition_is_negative) {
4584 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4585 }
4586 socket_only_conditions = TRUE;
4587 break;
4588 }
4589 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4590 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4591 if (condition_is_negative) {
4592 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4593 }
4594 socket_only_conditions = TRUE;
4595 break;
4596 }
4597 case NECP_POLICY_CONDITION_SCHEME_PORT: {
4598 master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4599 if (condition_is_negative) {
4600 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4601 }
4602 memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4603 socket_ip_conditions = TRUE;
4604 break;
4605 }
4606 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4607 if (condition_length > 0) {
4608 if (cond_signing_identifier == NULL) {
4609 cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4610 if (cond_signing_identifier != NULL) {
4611 master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4612 socket_only_conditions = TRUE;
4613 if (condition_is_negative) {
4614 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4615 }
4616 }
4617 }
4618 }
4619 break;
4620 }
4621 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4622 if (condition_length >= sizeof(u_int16_t)) {
4623 master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4624 if (condition_is_negative) {
4625 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4626 }
4627 memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4628 socket_ip_conditions = TRUE;
4629 }
4630 break;
4631 }
4632 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4633 master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4634 if (condition_is_negative) {
4635 master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4636 }
4637 socket_only_conditions = TRUE;
4638 break;
4639 }
4640 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4641 master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4642 if (condition_is_negative) {
4643 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4644 }
4645 socket_only_conditions = TRUE;
4646 break;
4647 }
4648 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4649 if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4650 u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4651 memcpy(&flags, condition_value, sizeof(flags));
4652 cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4653 cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4654 cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4655 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4656 if (condition_is_negative) {
4657 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4658 }
4659 socket_ip_conditions = TRUE;
4660 }
4661 break;
4662 }
4663 default: {
4664 break;
4665 }
4666 }
4667
4668 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4669 }
4670
4671 // Process result
4672 ultimate_result = necp_policy_get_result_type(policy);
4673 switch (ultimate_result) {
4674 case NECP_POLICY_RESULT_PASS: {
4675 u_int32_t pass_flags = 0;
4676 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4677 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4678 ultimate_result_parameter.pass_flags = pass_flags;
4679 }
4680 }
4681 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4682 socket_layer_non_id_conditions = TRUE;
4683 ip_output_layer_id_condition = TRUE;
4684 } else if (socket_ip_conditions) {
4685 socket_layer_non_id_conditions = TRUE;
4686 ip_output_layer_id_condition = TRUE;
4687 ip_output_layer_non_id_conditions = TRUE;
4688 }
4689 break;
4690 }
4691 case NECP_POLICY_RESULT_DROP: {
4692 u_int32_t drop_flags = 0;
4693 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4694 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4695 ultimate_result_parameter.drop_flags = drop_flags;
4696 }
4697 }
4698 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4699 socket_layer_non_id_conditions = TRUE;
4700 } else if (socket_ip_conditions) {
4701 socket_layer_non_id_conditions = TRUE;
4702 ip_output_layer_non_id_conditions = TRUE;
4703 ip_output_layer_non_id_only = TRUE; // Only apply drop to packets that didn't go through socket layer
4704 }
4705 break;
4706 }
4707 case NECP_POLICY_RESULT_SKIP: {
4708 u_int32_t skip_policy_order = 0;
4709 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4710 ultimate_result_parameter.skip_policy_order = skip_policy_order;
4711 }
4712
4713 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4714 socket_layer_non_id_conditions = TRUE;
4715 ip_output_layer_id_condition = TRUE;
4716 } else if (socket_ip_conditions) {
4717 socket_layer_non_id_conditions = TRUE;
4718 ip_output_layer_non_id_conditions = TRUE;
4719 }
4720 break;
4721 }
4722 case NECP_POLICY_RESULT_SOCKET_DIVERT:
4723 case NECP_POLICY_RESULT_SOCKET_FILTER: {
4724 u_int32_t control_unit = 0;
4725 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4726 ultimate_result_parameter.flow_divert_control_unit = control_unit;
4727 }
4728 socket_layer_non_id_conditions = TRUE;
4729 break;
4730 }
4731 case NECP_POLICY_RESULT_IP_TUNNEL: {
4732 struct necp_policy_result_ip_tunnel tunnel_parameters;
4733 u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4734 if (tunnel_parameters_length > sizeof(u_int32_t) &&
4735 tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4736 necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4737 ifnet_t __single tunnel_interface = NULL;
4738 tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0; // Make sure the string is NULL terminated
4739 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4740 ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4741 ifnet_release(tunnel_interface);
4742 }
4743
4744 secondary_result = tunnel_parameters.secondary_result;
4745 if (secondary_result) {
4746 cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4747 }
4748 }
4749
4750 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4751 socket_layer_non_id_conditions = TRUE;
4752 ip_output_layer_id_condition = TRUE;
4753 if (secondary_result) {
4754 ip_output_layer_tunnel_condition_from_id = TRUE;
4755 }
4756 } else if (socket_ip_conditions) {
4757 socket_layer_non_id_conditions = TRUE;
4758 ip_output_layer_id_condition = TRUE;
4759 ip_output_layer_non_id_conditions = TRUE;
4760 if (secondary_result) {
4761 ip_output_layer_tunnel_condition_from_id = TRUE;
4762 ip_output_layer_tunnel_condition_from_non_id = TRUE;
4763 }
4764 }
4765 break;
4766 }
4767 case NECP_POLICY_RESULT_USE_NETAGENT:
4768 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4769 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4770 uuid_t netagent_uuid;
4771 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4772 ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
4773 if (ultimate_result_parameter.netagent_id != 0) {
4774 uuid_copy(policy->applied_result_uuid, netagent_uuid);
4775 socket_layer_non_id_conditions = TRUE;
4776 }
4777 }
4778 break;
4779 }
4780 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4781 u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4782 if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4783 char interface_name[IFXNAMSIZ];
4784 ifnet_t __single scope_interface = NULL;
4785 necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4786 interface_name[interface_name_length - 1] = 0; // Make sure the string is NULL terminated
4787 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4788 ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4789 socket_layer_non_id_conditions = TRUE;
4790 ifnet_release(scope_interface);
4791 }
4792 }
4793 break;
4794 }
4795 case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4796 socket_layer_non_id_conditions = TRUE;
4797 break;
4798 }
4799 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4800 socket_layer_non_id_conditions = TRUE;
4801 break;
4802 }
4803 case NECP_POLICY_RESULT_ROUTE_RULES: {
4804 if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4805 bool has_socket_only_actions = FALSE;
4806 u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4807 if (route_rule_id > 0) {
4808 policy->applied_route_rules_id = route_rule_id;
4809 ultimate_result_parameter.route_rule_id = route_rule_id;
4810 if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4811 socket_layer_non_id_conditions = TRUE;
4812 } else if (socket_ip_conditions) {
4813 socket_layer_non_id_conditions = TRUE;
4814 ip_output_layer_non_id_conditions = TRUE;
4815 ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4816 }
4817 }
4818 }
4819 break;
4820 }
4821 default: {
4822 break;
4823 }
4824 }
4825
4826 if (socket_layer_non_id_conditions) {
4827 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);
4828
4829 if (policy_id == 0) {
4830 NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4831 goto fail;
4832 }
4833
4834 cond_ip_output_layer_id = policy_id;
4835 policy->kernel_socket_policies[0] = policy_id;
4836 }
4837
4838 if (ip_output_layer_non_id_conditions) {
4839 u_int64_t condition_mask = master_condition_mask;
4840 if (ip_output_layer_non_id_only) {
4841 condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4842 }
4843
4844 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);
4845
4846 if (policy_id == 0) {
4847 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4848 goto fail;
4849 }
4850
4851 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4852 }
4853
4854 if (ip_output_layer_id_condition) {
4855 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);
4856
4857 if (policy_id == 0) {
4858 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4859 goto fail;
4860 }
4861
4862 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4863 }
4864
4865 // Extra policies for IP Output tunnels for when packets loop back
4866 if (ip_output_layer_tunnel_condition_from_id) {
4867 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);
4868
4869 if (policy_id == 0) {
4870 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4871 goto fail;
4872 }
4873
4874 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4875 }
4876
4877 if (ip_output_layer_tunnel_condition_from_id) {
4878 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);
4879
4880 if (policy_id == 0) {
4881 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4882 goto fail;
4883 }
4884
4885 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4886 }
4887
4888 policy->applied = TRUE;
4889 policy->pending_update = FALSE;
4890 return TRUE;
4891
4892 fail:
4893 return FALSE;
4894 }
4895
4896 static void
necp_policy_apply_all(struct necp_session * session)4897 necp_policy_apply_all(struct necp_session *session)
4898 {
4899 struct necp_session_policy *policy = NULL;
4900 struct necp_session_policy *temp_policy = NULL;
4901 struct kev_necp_policies_changed_data kev_data;
4902 kev_data.changed_count = 0;
4903
4904 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4905
4906 // Remove exisiting applied policies
4907 if (session->dirty) {
4908 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4909 if (policy->pending_deletion) {
4910 if (policy->applied) {
4911 necp_policy_unapply(policy);
4912 }
4913 // Delete the policy
4914 necp_policy_delete(session, policy);
4915 } else if (!policy->applied) {
4916 necp_policy_apply(session, policy);
4917 } else if (policy->pending_update) {
4918 // Must have been applied, but needs an update. Remove and re-add.
4919 necp_policy_unapply(policy);
4920 necp_policy_apply(session, policy);
4921 }
4922 }
4923
4924 necp_kernel_socket_policies_update_uuid_table();
4925 necp_kernel_socket_policies_reprocess();
4926 necp_kernel_ip_output_policies_reprocess();
4927
4928 // Clear dirty bit flags
4929 session->dirty = FALSE;
4930 }
4931
4932 lck_rw_done(&necp_kernel_policy_lock);
4933
4934 necp_update_all_clients();
4935 necp_post_change_event(&kev_data);
4936
4937 if (necp_debug) {
4938 NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4939 }
4940 }
4941
4942 // Kernel Policy Management
4943 // ---------------------
4944 // Kernel policies are derived from session policies
4945 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4946 necp_kernel_policy_get_new_id(bool socket_level)
4947 {
4948 static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4949 static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4950
4951 necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4952
4953 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4954
4955 if (socket_level) {
4956 bool wrapped = FALSE;
4957 do {
4958 necp_last_kernel_socket_policy_id++;
4959 if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4960 necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4961 if (wrapped) {
4962 // Already wrapped, give up
4963 NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4964 return NECP_KERNEL_POLICY_ID_NONE;
4965 }
4966 necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4967 wrapped = TRUE;
4968 }
4969 newid = necp_last_kernel_socket_policy_id;
4970 } while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4971 } else {
4972 bool wrapped = FALSE;
4973 do {
4974 necp_last_kernel_ip_policy_id++;
4975 if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4976 if (wrapped) {
4977 // Already wrapped, give up
4978 NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4979 return NECP_KERNEL_POLICY_ID_NONE;
4980 }
4981 necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4982 wrapped = TRUE;
4983 }
4984 newid = necp_last_kernel_ip_policy_id;
4985 } while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4986 }
4987
4988 if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4989 NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4990 return NECP_KERNEL_POLICY_ID_NONE;
4991 }
4992
4993 return newid;
4994 }
4995
4996 #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)
4997
4998 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)4999 necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement __null_terminated, u_int32_t cond_account_id, char *cond_domain __null_terminated, u_int32_t cond_domain_filter, char *cond_url __null_terminated, pid_t cond_pid, int32_t cond_pid_version, uid_t cond_uid, uid_t cond_real_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union * __single cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier __null_terminated, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
5000 {
5001 struct necp_kernel_socket_policy *new_kernel_policy = NULL;
5002 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5003
5004 new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
5005
5006 new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
5007 new_kernel_policy->order = order;
5008 new_kernel_policy->session_order = session_order;
5009 new_kernel_policy->session_pid = session_pid;
5010
5011 // Sanitize condition mask
5012 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
5013 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
5014 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
5015 }
5016 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
5017 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
5018 }
5019 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
5020 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
5021 }
5022 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
5023 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
5024 }
5025 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
5026 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
5027 }
5028 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
5029 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
5030 }
5031 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
5032 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
5033 }
5034 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
5035
5036 // Set condition values
5037 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
5038 new_kernel_policy->cond_app_id = cond_app_id;
5039 }
5040 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
5041 new_kernel_policy->cond_real_app_id = cond_real_app_id;
5042 }
5043 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
5044 new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
5045 }
5046 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
5047 new_kernel_policy->cond_account_id = cond_account_id;
5048 }
5049 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
5050 (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
5051 new_kernel_policy->cond_domain = cond_domain;
5052 new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
5053 }
5054 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
5055 new_kernel_policy->cond_domain_filter = cond_domain_filter;
5056 }
5057 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
5058 new_kernel_policy->cond_url = cond_url;
5059 }
5060 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
5061 new_kernel_policy->cond_pid = cond_pid;
5062 new_kernel_policy->cond_pid_version = cond_pid_version;
5063 }
5064 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
5065 new_kernel_policy->cond_uid = cond_uid;
5066 }
5067 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
5068 new_kernel_policy->cond_real_uid = cond_real_uid;
5069 }
5070 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
5071 if (cond_bound_interface) {
5072 ifnet_reference(cond_bound_interface);
5073 }
5074 new_kernel_policy->cond_bound_interface = cond_bound_interface;
5075 }
5076 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
5077 new_kernel_policy->cond_traffic_class = cond_traffic_class;
5078 }
5079 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
5080 new_kernel_policy->cond_protocol = cond_protocol;
5081 }
5082 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5083 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
5084 }
5085 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5086 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
5087 }
5088 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5089 new_kernel_policy->cond_local_prefix = cond_local_prefix;
5090 }
5091 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5092 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
5093 }
5094 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5095 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
5096 }
5097 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5098 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
5099 }
5100 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
5101 memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
5102 }
5103 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
5104 memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
5105 }
5106 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
5107 new_kernel_policy->cond_client_flags = cond_client_flags;
5108 }
5109 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
5110 new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
5111 }
5112 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
5113 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
5114 }
5115 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
5116 new_kernel_policy->cond_scheme_port = cond_scheme_port;
5117 }
5118 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
5119 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
5120 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
5121 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
5122 }
5123 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
5124 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
5125 }
5126
5127 new_kernel_policy->result = result;
5128 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
5129
5130 if (necp_debug) {
5131 NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
5132 }
5133 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
5134
5135 return new_kernel_policy ? new_kernel_policy->id : 0;
5136 }
5137
5138 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)5139 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
5140 {
5141 struct necp_kernel_socket_policy *kernel_policy = NULL;
5142 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5143
5144 if (policy_id == 0) {
5145 return NULL;
5146 }
5147
5148 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
5149 if (kernel_policy->id == policy_id) {
5150 return kernel_policy;
5151 }
5152 }
5153
5154 return NULL;
5155 }
5156
5157 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)5158 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
5159 {
5160 struct necp_kernel_socket_policy * __single policy = NULL;
5161 char * __indexable buffer = NULL;
5162 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5163
5164 policy = necp_kernel_socket_policy_find(policy_id);
5165 if (policy) {
5166 LIST_REMOVE(policy, chain);
5167
5168 if (policy->cond_bound_interface) {
5169 ifnet_release(policy->cond_bound_interface);
5170 policy->cond_bound_interface = NULL;
5171 }
5172
5173 if (policy->cond_domain) {
5174 buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
5175 kfree_data_addr(buffer);
5176 policy->cond_domain = NULL;
5177 }
5178
5179 if (policy->cond_url) {
5180 buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
5181 kfree_data_addr(buffer);
5182 policy->cond_url = NULL;
5183 }
5184
5185 if (policy->cond_custom_entitlement) {
5186 buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
5187 kfree_data_addr(buffer);
5188 policy->cond_custom_entitlement = NULL;
5189 }
5190
5191 if (policy->cond_signing_identifier) {
5192 buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
5193 kfree_data_addr(buffer);
5194 policy->cond_signing_identifier = NULL;
5195 }
5196
5197 zfree(necp_socket_policy_zone, policy);
5198 return TRUE;
5199 }
5200
5201 return FALSE;
5202 }
5203
5204 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)5205 __sized_by(MAX_RESULT_STRING_LEN)
5206 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)
5207 {
5208 uuid_string_t uuid_string;
5209 switch (result) {
5210 case NECP_KERNEL_POLICY_RESULT_NONE: {
5211 snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
5212 break;
5213 }
5214 case NECP_KERNEL_POLICY_RESULT_PASS: {
5215 snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
5216 break;
5217 }
5218 case NECP_KERNEL_POLICY_RESULT_SKIP: {
5219 snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
5220 break;
5221 }
5222 case NECP_KERNEL_POLICY_RESULT_DROP: {
5223 snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5224 break;
5225 }
5226 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5227 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5228 break;
5229 }
5230 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5231 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5232 break;
5233 }
5234 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5235 ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5236 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5237 break;
5238 }
5239 case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5240 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5241 break;
5242 }
5243 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5244 ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5245 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5246 break;
5247 }
5248 case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5249 snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5250 break;
5251 }
5252 case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5253 snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5254 break;
5255 }
5256 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5257 int index = 0;
5258 char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5259 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5260 if (route_rule != NULL) {
5261 for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5262 if (route_rule->exception_if_indices[index] != 0) {
5263 ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5264 snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5265 } else {
5266 memset(interface_names[index], 0, IFXNAMSIZ);
5267 }
5268 }
5269 switch (route_rule->default_action) {
5270 case NECP_ROUTE_RULE_DENY_INTERFACE:
5271 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5272 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)",
5273 (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5274 (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5275 (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5276 (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5277 (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5278 (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5279 (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5280 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5281 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5282 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5283 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5284 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5285 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5286 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5287 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5288 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5289 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5290 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5291 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5292 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5293 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5294 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5295 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5296 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5297 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5298 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5299 break;
5300 case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5301 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)",
5302 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5303 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5304 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5305 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5306 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5307 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5308 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5309 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5310 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5311 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5312 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5313 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5314 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5315 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5316 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5317 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5318 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5319 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5320 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5321 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5322 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5323 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5324 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5325 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5326 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5327 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5328 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5329 break;
5330 case NECP_ROUTE_RULE_QOS_MARKING:
5331 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)",
5332 (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5333 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5334 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5335 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5336 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5337 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5338 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5339 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5340 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5341 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5342 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5343 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5344 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5345 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5346 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5347 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5348 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5349 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5350 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5351 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5352 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5353 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5354 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5355 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5356 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5357 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5358 break;
5359 default:
5360 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5361 break;
5362 }
5363 }
5364 break;
5365 }
5366 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5367 bool found_mapping = FALSE;
5368 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5369 if (mapping != NULL) {
5370 uuid_unparse(mapping->uuid, uuid_string);
5371 found_mapping = TRUE;
5372 }
5373 snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5374 break;
5375 }
5376 case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5377 bool found_mapping = FALSE;
5378 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5379 if (mapping != NULL) {
5380 uuid_unparse(mapping->uuid, uuid_string);
5381 found_mapping = TRUE;
5382 }
5383 snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5384 break;
5385 }
5386 case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5387 bool found_mapping = FALSE;
5388 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5389 if (mapping != NULL) {
5390 uuid_unparse(mapping->uuid, uuid_string);
5391 found_mapping = TRUE;
5392 }
5393 snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5394 break;
5395 }
5396 default: {
5397 snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5398 break;
5399 }
5400 }
5401 return result_string;
5402 }
5403
5404 static void
necp_kernel_socket_policies_dump_all(void)5405 necp_kernel_socket_policies_dump_all(void)
5406 {
5407 if (necp_debug) {
5408 struct necp_kernel_socket_policy *policy = NULL;
5409 int policy_i;
5410 int app_i;
5411 char result_string[MAX_RESULT_STRING_LEN];
5412 char proc_name_string[MAXCOMLEN + 1];
5413 memset(result_string, 0, MAX_RESULT_STRING_LEN);
5414 memset(proc_name_string, 0, MAXCOMLEN + 1);
5415
5416 NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5417 NECPLOG0(LOG_DEBUG, "-----------\n");
5418 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5419 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5420 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5421 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));
5422 }
5423 if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5424 NECPLOG0(LOG_DEBUG, "-----------\n");
5425 }
5426
5427 NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5428 NECPLOG0(LOG_DEBUG, "-----------\n");
5429 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5430 NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5431 for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5432 policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5433 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5434 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));
5435 }
5436 NECPLOG0(LOG_DEBUG, "-----------\n");
5437 }
5438 }
5439 }
5440
5441 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5442 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5443 {
5444 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5445 // Drop always cancels out lower policies
5446 return TRUE;
5447 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5448 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5449 upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5450 upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5451 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5452 upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
5453 // Filters and route rules never cancel out lower policies
5454 return FALSE;
5455 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5456 if (upper_policy->session_order != lower_policy->session_order) {
5457 // A skip cannot override a policy of a different session
5458 return FALSE;
5459 } else {
5460 if (upper_policy->result_parameter.skip_policy_order == 0 ||
5461 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5462 // This policy is beyond the skip
5463 return FALSE;
5464 } else {
5465 // This policy is inside the skip
5466 return TRUE;
5467 }
5468 }
5469 }
5470
5471 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5472 return TRUE;
5473 }
5474
5475 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)5476 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5477 {
5478 bool can_skip = FALSE;
5479 u_int32_t highest_skip_session_order = 0;
5480 u_int32_t highest_skip_order = 0;
5481 int i;
5482 for (i = 0; i < valid_indices; i++) {
5483 struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5484
5485 // For policies in a skip window, we can't mark conflicting policies as unnecessary
5486 if (can_skip) {
5487 if (highest_skip_session_order != compared_policy->session_order ||
5488 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5489 // If we've moved on to the next session, or passed the skip window
5490 highest_skip_session_order = 0;
5491 highest_skip_order = 0;
5492 can_skip = FALSE;
5493 } else {
5494 // If this policy is also a skip, in can increase the skip window
5495 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5496 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5497 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5498 }
5499 }
5500 continue;
5501 }
5502 }
5503
5504 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5505 // This policy is a skip. Set the skip window accordingly
5506 can_skip = TRUE;
5507 highest_skip_session_order = compared_policy->session_order;
5508 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5509 }
5510
5511 // The result of the compared policy must be able to block out this policy result
5512 if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5513 continue;
5514 }
5515
5516 // If new policy matches All Interfaces, compared policy must also
5517 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5518 continue;
5519 }
5520
5521 // If new policy matches Local Networks, compared policy must also
5522 if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5523 policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5524 continue;
5525 }
5526
5527 // Default makes lower policies unecessary always
5528 if (compared_policy->condition_mask == 0) {
5529 return TRUE;
5530 }
5531
5532 // Compared must be more general than policy, and include only conditions within policy
5533 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5534 continue;
5535 }
5536
5537 // Negative conditions must match for the overlapping conditions
5538 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5539 continue;
5540 }
5541
5542 if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5543 compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5544 strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5545 continue;
5546 }
5547
5548 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5549 compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5550 continue;
5551 }
5552
5553 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5554 strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5555 continue;
5556 }
5557
5558 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5559 strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5560 continue;
5561 }
5562
5563 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5564 compared_policy->cond_account_id != policy->cond_account_id) {
5565 continue;
5566 }
5567
5568 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5569 compared_policy->cond_policy_id != policy->cond_policy_id) {
5570 continue;
5571 }
5572
5573 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5574 compared_policy->cond_app_id != policy->cond_app_id) {
5575 continue;
5576 }
5577
5578 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5579 compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5580 continue;
5581 }
5582
5583 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5584 (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5585 continue;
5586 }
5587
5588 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5589 compared_policy->cond_uid != policy->cond_uid) {
5590 continue;
5591 }
5592
5593 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5594 compared_policy->cond_real_uid != policy->cond_real_uid) {
5595 continue;
5596 }
5597
5598 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5599 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5600 continue;
5601 }
5602
5603 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5604 compared_policy->cond_protocol != policy->cond_protocol) {
5605 continue;
5606 }
5607
5608 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5609 compared_policy->cond_client_flags != policy->cond_client_flags) {
5610 continue;
5611 }
5612
5613 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5614 !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5615 compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5616 continue;
5617 }
5618
5619 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5620 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5621 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))) {
5622 continue;
5623 }
5624 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5625 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5626 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5627 continue;
5628 }
5629 }
5630 }
5631
5632 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5633 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5634 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))) {
5635 continue;
5636 }
5637 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5638 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5639 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5640 continue;
5641 }
5642 }
5643 }
5644
5645 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5646 memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5647 continue;
5648 }
5649
5650 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5651 memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5652 continue;
5653 }
5654
5655 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5656 memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5657 continue;
5658 }
5659
5660 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5661 memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5662 continue;
5663 }
5664
5665 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5666 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5667 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5668 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5669 continue;
5670 }
5671
5672 return TRUE;
5673 }
5674
5675 return FALSE;
5676 }
5677
5678 static bool
necp_kernel_socket_policies_reprocess(void)5679 necp_kernel_socket_policies_reprocess(void)
5680 {
5681 int app_i;
5682 int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5683 int app_layer_current_free_index = 0;
5684 struct necp_kernel_socket_policy *kernel_policy = NULL;
5685
5686 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5687
5688 // Reset mask to 0
5689 necp_kernel_application_policies_condition_mask = 0;
5690 necp_kernel_socket_policies_condition_mask = 0;
5691 necp_kernel_application_policies_count = 0;
5692 necp_kernel_socket_policies_count = 0;
5693 necp_kernel_socket_policies_non_app_count = 0;
5694
5695 // Reset all maps to NULL
5696 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5697 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5698 kfree_type(struct necp_kernel_socket_policy *,
5699 necp_kernel_socket_policies_map_counts[app_i] + 1,
5700 necp_kernel_socket_policies_map[app_i]);
5701 necp_kernel_socket_policies_map[app_i] = NULL;
5702 }
5703
5704 // Init counts
5705 necp_kernel_socket_policies_map_counts[app_i] = 0;
5706 }
5707 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5708 kfree_type(struct necp_kernel_socket_policy *,
5709 necp_kernel_socket_policies_app_layer_map_count + 1,
5710 necp_kernel_socket_policies_app_layer_map);
5711 }
5712 necp_kernel_socket_policies_app_layer_map = NULL;
5713 necp_kernel_socket_policies_app_layer_map_count = 0;
5714
5715 // Create masks and counts
5716 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5717 // App layer mask/count
5718 necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5719 necp_kernel_application_policies_count++;
5720 necp_kernel_socket_policies_app_layer_map_count++;
5721
5722 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5723 // Agent type conditions only apply to app layer
5724 continue;
5725 }
5726
5727 // Update socket layer bucket mask/counts
5728 necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5729 necp_kernel_socket_policies_count++;
5730
5731 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5732 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5733 necp_kernel_socket_policies_non_app_count++;
5734 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5735 necp_kernel_socket_policies_map_counts[app_i]++;
5736 }
5737 } else {
5738 necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5739 }
5740 }
5741
5742 // Allocate maps
5743 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5744 if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5745 // Allocate a NULL-terminated array of policy pointers for each bucket
5746 necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5747 necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5748 if (necp_kernel_socket_policies_map[app_i] == NULL) {
5749 goto fail;
5750 }
5751 }
5752 bucket_current_free_index[app_i] = 0;
5753 }
5754 necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5755 necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5756 if (necp_kernel_socket_policies_app_layer_map == NULL) {
5757 goto fail;
5758 }
5759
5760 // Fill out maps
5761 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5762 // Add app layer policies
5763 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5764 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5765 app_layer_current_free_index++;
5766 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5767 }
5768
5769 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5770 // Agent type conditions only apply to app layer
5771 continue;
5772 }
5773
5774 // Add socket policies
5775 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5776 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5777 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5778 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])) {
5779 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5780 bucket_current_free_index[app_i]++;
5781 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5782 }
5783 }
5784 } else {
5785 app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5786 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])) {
5787 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5788 bucket_current_free_index[app_i]++;
5789 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5790 }
5791 }
5792 }
5793 necp_kernel_socket_policies_dump_all();
5794 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5795 return TRUE;
5796
5797 fail:
5798 // Free memory, reset masks to 0
5799 necp_kernel_application_policies_condition_mask = 0;
5800 necp_kernel_socket_policies_condition_mask = 0;
5801 necp_kernel_application_policies_count = 0;
5802 necp_kernel_socket_policies_count = 0;
5803 necp_kernel_socket_policies_non_app_count = 0;
5804 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5805 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5806 kfree_type(struct necp_kernel_socket_policy *,
5807 necp_kernel_socket_policies_map_counts[app_i] + 1,
5808 necp_kernel_socket_policies_map[app_i]);
5809 necp_kernel_socket_policies_map[app_i] = NULL;
5810 }
5811 necp_kernel_socket_policies_map_counts[app_i] = 0;
5812 }
5813 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5814 kfree_type(struct necp_kernel_socket_policy *,
5815 necp_kernel_socket_policies_app_layer_map_count + 1,
5816 necp_kernel_socket_policies_app_layer_map);
5817 necp_kernel_socket_policies_app_layer_map = NULL;
5818 }
5819 necp_kernel_socket_policies_app_layer_map_count = 0;
5820 return FALSE;
5821 }
5822
5823 static u_int32_t
necp_get_new_string_id(void)5824 necp_get_new_string_id(void)
5825 {
5826 static u_int32_t necp_last_string_id = 0;
5827
5828 u_int32_t newid = 0;
5829
5830 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5831
5832 bool wrapped = FALSE;
5833 do {
5834 necp_last_string_id++;
5835 if (necp_last_string_id < 1) {
5836 if (wrapped) {
5837 // Already wrapped, give up
5838 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5839 return 0;
5840 }
5841 necp_last_string_id = 1;
5842 wrapped = TRUE;
5843 }
5844 newid = necp_last_string_id;
5845 } while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5846
5847 if (newid == 0) {
5848 NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5849 return 0;
5850 }
5851
5852 return newid;
5853 }
5854
5855 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5856 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5857 {
5858 struct necp_string_id_mapping *searchentry = NULL;
5859 struct necp_string_id_mapping *foundentry = NULL;
5860
5861 LIST_FOREACH(searchentry, list, chain) {
5862 if (strcmp(searchentry->string, string) == 0) {
5863 foundentry = searchentry;
5864 break;
5865 }
5866 }
5867
5868 return foundentry;
5869 }
5870
5871 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5872 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5873 {
5874 struct necp_string_id_mapping *searchentry = NULL;
5875 struct necp_string_id_mapping *foundentry = NULL;
5876
5877 LIST_FOREACH(searchentry, list, chain) {
5878 if (searchentry->id == local_id) {
5879 foundentry = searchentry;
5880 break;
5881 }
5882 }
5883
5884 return foundentry;
5885 }
5886
5887 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5888 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5889 {
5890 u_int32_t string_id = 0;
5891 struct necp_string_id_mapping *existing_mapping = 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 string_id = existing_mapping->id;
5898 os_ref_retain_locked(&existing_mapping->refcount);
5899 } else {
5900 struct necp_string_id_mapping * __single new_mapping = NULL;
5901 new_mapping = kalloc_type(struct necp_string_id_mapping,
5902 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5903
5904 size_t length = strlen(string) + 1;
5905 char *buffer = kalloc_data(length, Z_WAITOK);
5906 if (buffer != NULL) {
5907 strlcpy(buffer, string, length);
5908 new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5909 new_mapping->id = necp_get_new_string_id();
5910 os_ref_init(&new_mapping->refcount, &necp_refgrp);
5911 LIST_INSERT_HEAD(list, new_mapping, chain);
5912 string_id = new_mapping->id;
5913 } else {
5914 kfree_type(struct necp_string_id_mapping, new_mapping);
5915 new_mapping = NULL;
5916 }
5917 }
5918 return string_id;
5919 }
5920
5921 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5922 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5923 {
5924 struct necp_string_id_mapping * __single existing_mapping = NULL;
5925 char * __indexable buffer = NULL;
5926
5927 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5928
5929 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5930 if (existing_mapping != NULL) {
5931 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5932 LIST_REMOVE(existing_mapping, chain);
5933 buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5934 kfree_data_addr(buffer);
5935 kfree_type(struct necp_string_id_mapping, existing_mapping);
5936 }
5937 return TRUE;
5938 }
5939
5940 return FALSE;
5941 }
5942
5943 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5944 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5945 {
5946 struct necp_domain_filter *searchfilter = NULL;
5947 struct necp_domain_filter *foundfilter = NULL;
5948
5949 LIST_FOREACH(searchfilter, list, chain) {
5950 if (searchfilter->id == filter_id) {
5951 foundfilter = searchfilter;
5952 break;
5953 }
5954 }
5955
5956 return foundfilter;
5957 }
5958
5959 static u_int32_t
necp_get_new_domain_filter_id(void)5960 necp_get_new_domain_filter_id(void)
5961 {
5962 static u_int32_t necp_last_filter_id = 0;
5963
5964 u_int32_t newid = 0;
5965
5966 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5967
5968 bool wrapped = FALSE;
5969 do {
5970 // Scope id within its space
5971 if (++necp_last_filter_id > NECP_DOMAIN_FILTER_ID_MAX) {
5972 necp_last_filter_id = 0;
5973 }
5974 if (necp_last_filter_id < 1) {
5975 if (wrapped) {
5976 // Already wrapped, give up
5977 NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5978 return 0;
5979 }
5980 necp_last_filter_id = 1;
5981 wrapped = TRUE;
5982 }
5983 newid = necp_last_filter_id;
5984 } while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5985
5986 if (newid == 0) {
5987 NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5988 return 0;
5989 }
5990
5991 return newid;
5992 }
5993
5994 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)5995 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5996 {
5997 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5998
5999 struct necp_domain_filter *new_filter = NULL;
6000 new_filter = kalloc_type(struct necp_domain_filter,
6001 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6002
6003 new_filter->filter = filter;
6004 new_filter->id = necp_get_new_domain_filter_id();
6005 LIST_INSERT_HEAD(list, new_filter, chain);
6006 LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
6007 os_ref_init(&new_filter->refcount, &necp_refgrp);
6008
6009 return new_filter->id;
6010 }
6011
6012 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)6013 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
6014 {
6015 struct necp_domain_filter * __single existing_filter = NULL;
6016
6017 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6018
6019 existing_filter = necp_lookup_domain_filter(list, filter_id);
6020 if (existing_filter != NULL) {
6021 if (os_ref_release_locked(&existing_filter->refcount) == 0) {
6022 LIST_REMOVE(existing_filter, chain);
6023 LIST_REMOVE(existing_filter, owner_chain);
6024 net_bloom_filter_destroy(existing_filter->filter);
6025 kfree_type(struct necp_domain_filter, existing_filter);
6026 }
6027 return true;
6028 }
6029
6030 return false;
6031 }
6032
6033 static struct necp_domain_trie *
necp_lookup_domain_trie(struct necp_domain_trie_list * list,u_int32_t id)6034 necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id)
6035 {
6036 struct necp_domain_trie *searchTrie = NULL;
6037 struct necp_domain_trie *foundTrie = NULL;
6038
6039 LIST_FOREACH(searchTrie, list, chain) {
6040 if (searchTrie->id == id) {
6041 foundTrie = searchTrie;
6042 break;
6043 }
6044 }
6045
6046 return foundTrie;
6047 }
6048
6049 static u_int32_t
necp_get_new_domain_trie_id(void)6050 necp_get_new_domain_trie_id(void)
6051 {
6052 static u_int32_t necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START;
6053 u_int32_t newid = necp_last_trie_id;
6054
6055 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6056
6057 bool wrapped = FALSE;
6058 do {
6059 if (++necp_last_trie_id < NECP_DOMAIN_TRIE_ID_START + 1) {
6060 if (wrapped) {
6061 // Already wrapped, give up
6062 NECPLOG0(LOG_ERR, "Failed to find a free trie ID.\n");
6063 return 0;
6064 }
6065 necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START + 1;
6066 wrapped = TRUE;
6067 }
6068 newid = necp_last_trie_id;
6069 } while (necp_lookup_domain_trie(&necp_global_domain_trie_list, newid) != NULL); // If already used, keep trying
6070
6071 if (newid == NECP_DOMAIN_TRIE_ID_START) {
6072 NECPLOG0(LOG_ERR, "Allocate trie id failed.\n");
6073 return 0;
6074 }
6075
6076 return newid;
6077 }
6078
6079 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)6080 necp_create_domain_trie(struct necp_domain_trie_list *list,
6081 struct necp_domain_trie_list *owner_list,
6082 struct necp_domain_trie_request *trie_request, size_t trie_request_size)
6083 {
6084 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6085
6086 struct necp_domain_trie *new_trie = NULL;
6087 new_trie = kalloc_type(struct necp_domain_trie, Z_WAITOK | Z_ZERO | Z_NOFAIL);
6088 if (new_trie == NULL) {
6089 NECPLOG0(LOG_ERR, "Failed to allow domain trie\n");
6090 return 0;
6091 }
6092
6093 if (net_trie_init_with_mem(&new_trie->trie, trie_request->data, trie_request->total_mem_size,
6094 trie_request->nodes_mem_size, trie_request->maps_mem_size, trie_request->bytes_mem_size,
6095 trie_request->nodes_count, trie_request->maps_count, trie_request->bytes_count) == false) {
6096 NECPLOG0(LOG_ERR, "Failed to initialize domain trie\n");
6097 kfree_type(struct necp_domain_trie, new_trie);
6098 return 0;
6099 }
6100 new_trie->trie_request = trie_request;
6101 new_trie->trie_request_size = trie_request_size;
6102 new_trie->id = necp_get_new_domain_trie_id();
6103 new_trie->trie_request->id = new_trie->id;
6104 LIST_INSERT_HEAD(list, new_trie, chain);
6105 LIST_INSERT_HEAD(owner_list, new_trie, owner_chain);
6106
6107 os_ref_init(&new_trie->refcount, &necp_refgrp);
6108 necp_trie_count++;
6109 return new_trie->id;
6110 }
6111
6112 static void
necp_free_domain_trie(struct necp_domain_trie * existing_trie)6113 necp_free_domain_trie(struct necp_domain_trie *existing_trie)
6114 {
6115 if (existing_trie != NULL) {
6116 uint8_t *necp_trie_request_buffer = (uint8_t *)existing_trie->trie_request;
6117 kfree_data(necp_trie_request_buffer, existing_trie->trie_request_size);
6118 kfree_type(struct necp_domain_trie, existing_trie);
6119 }
6120 }
6121
6122 static bool
necp_remove_domain_trie(struct necp_domain_trie_list * list,__unused struct necp_domain_trie_list * owner_list,u_int32_t id)6123 necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id)
6124 {
6125 struct necp_domain_trie * __single existing_trie = NULL;
6126
6127 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6128
6129 existing_trie = necp_lookup_domain_trie(list, id);
6130 if (existing_trie != NULL) {
6131 if (os_ref_release_locked(&existing_trie->refcount) == 0) {
6132 LIST_REMOVE(existing_trie, chain);
6133 LIST_REMOVE(existing_trie, owner_chain);
6134 necp_free_domain_trie(existing_trie);
6135 necp_trie_count--;
6136 }
6137 return true;
6138 }
6139
6140 return false;
6141 }
6142
6143 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)6144 necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length)
6145 {
6146 size_t metadata_length = 0;
6147 const uint8_t * __sized_by(metadata_length) metadata = NULL;
6148
6149 struct necp_domain_trie *necp_trie = necp_lookup_domain_trie(list, id);
6150 if (necp_trie == NULL || necp_trie->trie_request == NULL) {
6151 return false;
6152 }
6153 Boolean reverse = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_REVERSE_SEARCH);
6154 Boolean allow_partial_match = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_ALLOW_PARTIAL_MATCH);
6155 return net_trie_search(&necp_trie->trie, (const uint8_t *)domain, length,
6156 &metadata, &metadata_length, reverse, allow_partial_match, necp_trie->trie_request->partial_match_terminator, NULL, NULL) != NULL_TRIE_IDX;
6157 }
6158
6159 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
6160 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
6161 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)6162 necp_get_new_route_rule_id(bool aggregate)
6163 {
6164 static u_int32_t necp_last_route_rule_id = 0;
6165 static u_int32_t necp_last_aggregate_route_rule_id = 0;
6166
6167 u_int32_t newid = 0;
6168
6169 if (!aggregate) {
6170 // Main necp_kernel_policy_lock protects non-aggregate rule IDs
6171 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6172
6173 bool wrapped = FALSE;
6174 do {
6175 necp_last_route_rule_id++;
6176 if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
6177 necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6178 if (wrapped) {
6179 // Already wrapped, give up
6180 NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
6181 return 0;
6182 }
6183 necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
6184 wrapped = TRUE;
6185 }
6186 newid = necp_last_route_rule_id;
6187 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6188 } else {
6189 // necp_route_rule_lock protects aggregate rule IDs
6190 LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
6191
6192 bool wrapped = FALSE;
6193 do {
6194 necp_last_aggregate_route_rule_id++;
6195 if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6196 if (wrapped) {
6197 // Already wrapped, give up
6198 NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
6199 return 0;
6200 }
6201 necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
6202 wrapped = TRUE;
6203 }
6204 newid = necp_last_aggregate_route_rule_id;
6205 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6206 }
6207
6208 if (newid == 0) {
6209 NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
6210 return 0;
6211 }
6212
6213 return newid;
6214 }
6215
6216 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)6217 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6218 {
6219 struct necp_route_rule *searchentry = NULL;
6220 struct necp_route_rule *foundentry = NULL;
6221
6222 LIST_FOREACH(searchentry, list, chain) {
6223 if (searchentry->id == route_rule_id) {
6224 foundentry = searchentry;
6225 break;
6226 }
6227 }
6228
6229 return foundentry;
6230 }
6231
6232 static struct necp_route_rule *
necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list * list,u_int8_t default_action,u_int8_t cellular_action,u_int8_t wifi_action,u_int8_t wired_action,u_int8_t expensive_action,u_int8_t constrained_action,u_int8_t companion_action,u_int8_t vpn_action,u_int32_t * __indexable if_indices,u_int8_t * __indexable if_actions,uuid_t netagent_uuid,uuid_t match_netagent_uuid,u_int32_t control_unit,u_int32_t effective_type)6233 necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list *list, u_int8_t default_action, u_int8_t cellular_action, u_int8_t wifi_action, u_int8_t wired_action, u_int8_t expensive_action, u_int8_t constrained_action, u_int8_t companion_action, u_int8_t vpn_action, u_int32_t * __indexable if_indices, u_int8_t * __indexable if_actions, uuid_t netagent_uuid, uuid_t match_netagent_uuid, u_int32_t control_unit, u_int32_t effective_type)
6234 {
6235 struct necp_route_rule *searchentry = NULL;
6236 struct necp_route_rule *foundentry = NULL;
6237
6238 LIST_FOREACH(searchentry, list, chain) {
6239 if (searchentry->default_action == default_action &&
6240 searchentry->cellular_action == cellular_action &&
6241 searchentry->wifi_action == wifi_action &&
6242 searchentry->wired_action == wired_action &&
6243 searchentry->expensive_action == expensive_action &&
6244 searchentry->constrained_action == constrained_action &&
6245 searchentry->companion_action == companion_action &&
6246 searchentry->vpn_action == vpn_action &&
6247 searchentry->control_unit == control_unit &&
6248 searchentry->effective_type == effective_type) {
6249 bool match_failed = FALSE;
6250 size_t index_a = 0;
6251 size_t index_b = 0;
6252 size_t count_a = 0;
6253 size_t count_b = 0;
6254 for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
6255 bool found_index = FALSE;
6256 if (searchentry->exception_if_indices[index_a] == 0) {
6257 break;
6258 }
6259 count_a++;
6260 for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
6261 if (if_indices[index_b] == 0) {
6262 break;
6263 }
6264 if (index_b >= count_b) {
6265 count_b = index_b + 1;
6266 }
6267 if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
6268 searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
6269 found_index = TRUE;
6270 break;
6271 }
6272 }
6273 if (!found_index) {
6274 match_failed = TRUE;
6275 break;
6276 }
6277 }
6278
6279 if (match_failed || count_a != count_b) {
6280 continue;
6281 }
6282
6283 bool has_agent_a = !uuid_is_null(netagent_uuid);
6284 bool has_agent_b = (searchentry->netagent_id != 0);
6285 if (has_agent_a != has_agent_b) {
6286 continue;
6287 }
6288
6289 if (has_agent_a) {
6290 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
6291 if (mapping == NULL) {
6292 // Bad mapping, doesn't match
6293 continue;
6294 }
6295 if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
6296 // UUIDs don't match
6297 continue;
6298 }
6299 }
6300
6301 bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
6302 bool has_match_agent_b = (searchentry->match_netagent_id != 0);
6303 if (has_match_agent_a != has_match_agent_b) {
6304 continue;
6305 }
6306
6307 if (has_match_agent_a) {
6308 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->match_netagent_id);
6309 if (mapping == NULL) {
6310 // Bad mapping, doesn't match
6311 continue;
6312 }
6313 if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
6314 // UUIDs don't match
6315 continue;
6316 }
6317 }
6318
6319 // Rules match!
6320 foundentry = searchentry;
6321 break;
6322 }
6323 }
6324
6325 return foundentry;
6326 }
6327
6328 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)6329 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,
6330 bool *has_socket_only_actions)
6331 {
6332 size_t offset = 0;
6333 u_int32_t route_rule_id = 0;
6334 struct necp_route_rule *existing_rule = NULL;
6335 u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
6336 u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
6337 u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
6338 u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
6339 u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
6340 u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
6341 u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
6342 u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
6343 u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
6344 size_t num_valid_indices = 0;
6345 memset(&if_indices, 0, sizeof(if_indices));
6346 u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
6347 memset(&if_actions, 0, sizeof(if_actions));
6348
6349 uuid_t netagent_uuid = {};
6350
6351 uuid_t match_netagent_uuid = {};
6352 uint32_t control_unit = 0;
6353 uint32_t effective_type = 0;
6354
6355 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6356
6357 if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6358 return 0;
6359 }
6360
6361 // Process rules
6362 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6363 ifnet_t __single rule_interface = NULL;
6364 char interface_name[IFXNAMSIZ];
6365 u_int32_t length = 0;
6366 u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6367
6368 if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6369 // Invalid TLV goes beyond end of the rules array
6370 break;
6371 }
6372
6373 // Increment offset for the next time through the loop
6374 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6375
6376 u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6377 u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6378 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6379 u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6380
6381 if (rule_action == NECP_ROUTE_RULE_NONE) {
6382 // Don't allow an explicit rule to be None action
6383 continue;
6384 }
6385
6386 if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6387 rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6388 if (rule_length < sizeof(uuid_t)) {
6389 // Too short, skip
6390 continue;
6391 }
6392
6393 if (!uuid_is_null(netagent_uuid)) {
6394 if (uuid_compare(netagent_uuid, rule_value) != 0) {
6395 // UUIDs don't match, skip
6396 continue;
6397 }
6398 } else {
6399 // Copy out agent UUID
6400 memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6401 }
6402
6403 // Adjust remaining length
6404 rule_value += sizeof(netagent_uuid);
6405 rule_length -= sizeof(netagent_uuid);
6406 *has_socket_only_actions = true;
6407 } else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6408 if (rule_length < sizeof(control_unit)) {
6409 // Too short, skip
6410 continue;
6411 }
6412
6413 memcpy(&control_unit, rule_value, sizeof(control_unit));
6414
6415 // Adjust remaining length
6416 rule_value += sizeof(control_unit);
6417 rule_length -= sizeof(control_unit);
6418 *has_socket_only_actions = true;
6419 } else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6420 if (rule_length < sizeof(effective_type)) {
6421 // Too short, skip
6422 continue;
6423 }
6424
6425 memcpy(&effective_type, rule_value, sizeof(effective_type));
6426
6427 // Adjust remaining length
6428 rule_value += sizeof(effective_type);
6429 rule_length -= sizeof(effective_type);
6430 }
6431
6432 if (rule_length == 0) {
6433 if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6434 cellular_action = rule_action;
6435 }
6436 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6437 wifi_action = rule_action;
6438 }
6439 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6440 wired_action = rule_action;
6441 }
6442 if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6443 expensive_action = rule_action;
6444 }
6445 if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6446 constrained_action = rule_action;
6447 }
6448 if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6449 companion_action = rule_action;
6450 }
6451 if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6452 vpn_action = rule_action;
6453 }
6454 if (rule_flags == 0) {
6455 default_action = rule_action;
6456 }
6457 continue;
6458 } else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6459 if (rule_length < sizeof(uuid_t)) {
6460 // Too short, skip
6461 continue;
6462 }
6463
6464 // Store the netagent UUID to match
6465 memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6466 // If the data is exactly a UUID, this is the default action
6467 if (rule_length == sizeof(uuid_t)) {
6468 default_action = rule_action;
6469 continue;
6470 }
6471
6472 // If the data is longer than a UUID, this also includes an interface name
6473 // Adjust remaining length to make sure the interface name is picked up below
6474 rule_value += sizeof(uuid_t);
6475 rule_length -= sizeof(uuid_t);
6476 }
6477
6478 if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6479 continue;
6480 }
6481
6482 if (rule_length <= IFXNAMSIZ) {
6483 memcpy(interface_name, rule_value, rule_length);
6484 interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6485 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6486 if_actions[num_valid_indices] = rule_action;
6487 if_indices[num_valid_indices++] = rule_interface->if_index;
6488 ifnet_release(rule_interface);
6489 }
6490 }
6491 }
6492
6493 existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, companion_action, vpn_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit, effective_type);
6494 if (existing_rule != NULL) {
6495 route_rule_id = existing_rule->id;
6496 os_ref_retain_locked(&existing_rule->refcount);
6497 } else {
6498 struct necp_route_rule *new_rule = NULL;
6499 new_rule = kalloc_type(struct necp_route_rule,
6500 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6501 route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6502 if (!uuid_is_null(netagent_uuid)) {
6503 new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
6504 }
6505 if (!uuid_is_null(match_netagent_uuid)) {
6506 new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(match_netagent_uuid);
6507 }
6508 new_rule->effective_type = effective_type;
6509 new_rule->control_unit = control_unit;
6510 new_rule->default_action = default_action;
6511 new_rule->cellular_action = cellular_action;
6512 new_rule->wifi_action = wifi_action;
6513 new_rule->wired_action = wired_action;
6514 new_rule->expensive_action = expensive_action;
6515 new_rule->constrained_action = constrained_action;
6516 new_rule->companion_action = companion_action;
6517 new_rule->vpn_action = vpn_action;
6518 memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6519 memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6520 os_ref_init(&new_rule->refcount, &necp_refgrp);
6521 LIST_INSERT_HEAD(list, new_rule, chain);
6522 }
6523 return route_rule_id;
6524 }
6525
6526 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6527 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6528 {
6529 if (rule_id) {
6530 lck_rw_lock_exclusive(&necp_route_rule_lock);
6531
6532 struct necp_aggregate_route_rule * __single existing_rule = NULL;
6533 struct necp_aggregate_route_rule *tmp_rule = NULL;
6534
6535 LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6536 int index = 0;
6537 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6538 u_int32_t route_rule_id = existing_rule->rule_ids[index];
6539 if (route_rule_id == rule_id) {
6540 LIST_REMOVE(existing_rule, chain);
6541 kfree_type(struct necp_aggregate_route_rule, existing_rule);
6542 break;
6543 }
6544 }
6545 }
6546
6547 lck_rw_done(&necp_route_rule_lock);
6548 }
6549 }
6550
6551 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6552 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6553 {
6554 struct necp_route_rule * __single existing_rule = NULL;
6555
6556 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6557
6558 existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6559 if (existing_rule != NULL) {
6560 if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6561 necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6562 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
6563 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->match_netagent_id);
6564 LIST_REMOVE(existing_rule, chain);
6565 kfree_type(struct necp_route_rule, existing_rule);
6566 }
6567 return TRUE;
6568 }
6569
6570 return FALSE;
6571 }
6572
6573 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6574 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6575 {
6576 struct necp_aggregate_route_rule *searchentry = NULL;
6577 struct necp_aggregate_route_rule *foundentry = NULL;
6578
6579 lck_rw_lock_shared(&necp_route_rule_lock);
6580
6581 LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6582 if (searchentry->id == route_rule_id) {
6583 foundentry = searchentry;
6584 break;
6585 }
6586 }
6587
6588 lck_rw_done(&necp_route_rule_lock);
6589
6590 return foundentry;
6591 }
6592
6593 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6594 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6595 {
6596 u_int32_t aggregate_route_rule_id = 0;
6597 struct necp_aggregate_route_rule *new_rule = NULL;
6598 struct necp_aggregate_route_rule *existing_rule = NULL;
6599
6600 lck_rw_lock_exclusive(&necp_route_rule_lock);
6601
6602 // Check if the rule already exists
6603 LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6604 if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6605 lck_rw_done(&necp_route_rule_lock);
6606 return existing_rule->id;
6607 }
6608 }
6609
6610 new_rule = kalloc_type(struct necp_aggregate_route_rule,
6611 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6612 aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6613 new_rule->id = aggregate_route_rule_id;
6614 memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6615 LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6616 lck_rw_done(&necp_route_rule_lock);
6617
6618 return aggregate_route_rule_id;
6619 }
6620
6621 #define NECP_NULL_SERVICE_ID 1
6622 #define NECP_FIRST_VALID_SERVICE_ID 2
6623 #define NECP_FIRST_VALID_APP_ID UINT16_MAX
6624 static u_int32_t
necp_get_new_uuid_id(bool service)6625 necp_get_new_uuid_id(bool service)
6626 {
6627 static u_int32_t necp_last_service_uuid_id = 0;
6628 static u_int32_t necp_last_app_uuid_id = 0;
6629
6630 u_int32_t newid = 0;
6631
6632 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6633
6634 if (service) {
6635 bool wrapped = FALSE;
6636 do {
6637 necp_last_service_uuid_id++;
6638 if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
6639 necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
6640 if (wrapped) {
6641 // Already wrapped, give up
6642 NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
6643 return NECP_NULL_SERVICE_ID;
6644 }
6645 necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
6646 wrapped = TRUE;
6647 }
6648 newid = necp_last_service_uuid_id;
6649 } while (necp_uuid_lookup_uuid_with_service_id_locked(newid) != NULL); // If already used, keep trying
6650 } else {
6651 bool wrapped = FALSE;
6652 do {
6653 necp_last_app_uuid_id++;
6654 if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
6655 if (wrapped) {
6656 // Already wrapped, give up
6657 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
6658 return NECP_NULL_SERVICE_ID;
6659 }
6660 necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
6661 wrapped = TRUE;
6662 }
6663 newid = necp_last_app_uuid_id;
6664 } while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6665 }
6666
6667 if (newid == NECP_NULL_SERVICE_ID) {
6668 NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
6669 return NECP_NULL_SERVICE_ID;
6670 }
6671
6672 return newid;
6673 }
6674
6675 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6676 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6677 {
6678 struct necp_uuid_id_mapping *searchentry = NULL;
6679 struct necp_uuid_id_mapping *foundentry = NULL;
6680
6681 LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6682 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6683 foundentry = searchentry;
6684 break;
6685 }
6686 }
6687
6688 return foundentry;
6689 }
6690
6691 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6692 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6693 {
6694 struct necp_uuid_id_mapping *searchentry = NULL;
6695 struct necp_uuid_id_mapping *foundentry = NULL;
6696
6697 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6698 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--) {
6699 LIST_FOREACH(searchentry, uuid_list_head, chain) {
6700 if (searchentry->id == local_id) {
6701 foundentry = searchentry;
6702 break;
6703 }
6704 }
6705 }
6706
6707 return foundentry;
6708 }
6709
6710 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6711 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6712 {
6713 u_int32_t local_id = 0;
6714 struct necp_uuid_id_mapping *existing_mapping = NULL;
6715
6716 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6717
6718 if (allocated_mapping) {
6719 *allocated_mapping = FALSE;
6720 }
6721
6722 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6723 if (existing_mapping != NULL) {
6724 local_id = existing_mapping->id;
6725 os_ref_retain_locked(&existing_mapping->refcount);
6726 if (uuid_policy_table) {
6727 existing_mapping->table_usecount++;
6728 }
6729 } else {
6730 struct necp_uuid_id_mapping *new_mapping = NULL;
6731 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6732 Z_WAITOK | Z_NOFAIL);
6733 uuid_copy(new_mapping->uuid, uuid);
6734 new_mapping->id = necp_get_new_uuid_id(false);
6735 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6736 if (uuid_policy_table) {
6737 new_mapping->table_usecount = 1;
6738 } else {
6739 new_mapping->table_usecount = 0;
6740 }
6741
6742 LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6743
6744 if (allocated_mapping) {
6745 *allocated_mapping = TRUE;
6746 }
6747
6748 local_id = new_mapping->id;
6749 }
6750
6751 return local_id;
6752 }
6753
6754 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6755 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6756 {
6757 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6758
6759 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6760
6761 if (removed_mapping) {
6762 *removed_mapping = FALSE;
6763 }
6764
6765 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6766 if (existing_mapping != NULL) {
6767 if (uuid_policy_table) {
6768 existing_mapping->table_usecount--;
6769 }
6770 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6771 LIST_REMOVE(existing_mapping, chain);
6772 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6773 if (removed_mapping) {
6774 *removed_mapping = TRUE;
6775 }
6776 }
6777 return TRUE;
6778 }
6779
6780 return FALSE;
6781 }
6782
6783 static struct necp_uuid_id_mapping *
necp_uuid_get_null_service_id_mapping(void)6784 necp_uuid_get_null_service_id_mapping(void)
6785 {
6786 static struct necp_uuid_id_mapping null_mapping;
6787 uuid_clear(null_mapping.uuid);
6788 null_mapping.id = NECP_NULL_SERVICE_ID;
6789
6790 return &null_mapping;
6791 }
6792
6793 static struct necp_uuid_id_mapping *
necp_uuid_lookup_service_id_locked(uuid_t uuid)6794 necp_uuid_lookup_service_id_locked(uuid_t uuid)
6795 {
6796 struct necp_uuid_id_mapping *searchentry = NULL;
6797 struct necp_uuid_id_mapping *foundentry = NULL;
6798
6799 if (uuid_is_null(uuid)) {
6800 return necp_uuid_get_null_service_id_mapping();
6801 }
6802
6803 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6804 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6805 foundentry = searchentry;
6806 break;
6807 }
6808 }
6809
6810 return foundentry;
6811 }
6812
6813 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)6814 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
6815 {
6816 struct necp_uuid_id_mapping *searchentry = NULL;
6817 struct necp_uuid_id_mapping *foundentry = NULL;
6818
6819 if (local_id == NECP_NULL_SERVICE_ID) {
6820 return necp_uuid_get_null_service_id_mapping();
6821 }
6822
6823 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6824 if (searchentry->id == local_id) {
6825 foundentry = searchentry;
6826 break;
6827 }
6828 }
6829
6830 return foundentry;
6831 }
6832
6833 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid)6834 necp_create_uuid_service_id_mapping(uuid_t uuid)
6835 {
6836 u_int32_t local_id = 0;
6837 struct necp_uuid_id_mapping *existing_mapping = NULL;
6838
6839 if (uuid_is_null(uuid)) {
6840 return NECP_NULL_SERVICE_ID;
6841 }
6842
6843 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6844
6845 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6846 if (existing_mapping != NULL) {
6847 local_id = existing_mapping->id;
6848 os_ref_retain_locked(&existing_mapping->refcount);
6849 } else {
6850 struct necp_uuid_id_mapping *new_mapping = NULL;
6851 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6852 Z_WAITOK | Z_NOFAIL);
6853 uuid_copy(new_mapping->uuid, uuid);
6854 new_mapping->id = necp_get_new_uuid_id(true);
6855 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6856
6857 LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
6858
6859 local_id = new_mapping->id;
6860 }
6861
6862 return local_id;
6863 }
6864
6865 static bool
necp_remove_uuid_service_id_mapping(uuid_t uuid)6866 necp_remove_uuid_service_id_mapping(uuid_t uuid)
6867 {
6868 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6869
6870 if (uuid_is_null(uuid)) {
6871 return TRUE;
6872 }
6873
6874 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6875
6876 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6877 if (existing_mapping != NULL) {
6878 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6879 LIST_REMOVE(existing_mapping, chain);
6880 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6881 }
6882 return TRUE;
6883 }
6884
6885 return FALSE;
6886 }
6887
6888 static bool
necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)6889 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
6890 {
6891 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6892
6893 if (service_id == 0) {
6894 return TRUE;
6895 }
6896
6897 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6898
6899 existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
6900 if (existing_mapping != NULL) {
6901 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6902 LIST_REMOVE(existing_mapping, chain);
6903 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6904 }
6905 return TRUE;
6906 }
6907
6908 return FALSE;
6909 }
6910
6911 static bool
necp_kernel_socket_policies_update_uuid_table(void)6912 necp_kernel_socket_policies_update_uuid_table(void)
6913 {
6914 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6915
6916 if (necp_uuid_app_id_mappings_dirty) {
6917 uuid_t dummy_uuid = {};
6918 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6919 NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6920 return FALSE;
6921 }
6922
6923 if (necp_num_uuid_app_id_mappings > 0) {
6924 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6925 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--) {
6926 struct necp_uuid_id_mapping *mapping = NULL;
6927 LIST_FOREACH(mapping, uuid_list_head, chain) {
6928 if (mapping->table_usecount > 0 &&
6929 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6930 NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6931 }
6932 }
6933 }
6934 }
6935
6936 necp_uuid_app_id_mappings_dirty = FALSE;
6937 }
6938
6939 return TRUE;
6940 }
6941
6942 #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)
6943 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)6944 necp_kernel_ip_output_policy_add(necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_kernel_policy_id cond_policy_id, ifnet_t cond_bound_interface, u_int32_t cond_last_interface_index, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
6945 {
6946 struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6947 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6948
6949 new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6950 new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6951 new_kernel_policy->suborder = suborder;
6952 new_kernel_policy->order = order;
6953 new_kernel_policy->session_order = session_order;
6954 new_kernel_policy->session_pid = session_pid;
6955
6956 // Sanitize condition mask
6957 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6958 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6959 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6960 }
6961 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
6962 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
6963 }
6964 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6965 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6966 }
6967 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6968 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6969 }
6970 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6971
6972 // Set condition values
6973 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6974 new_kernel_policy->cond_policy_id = cond_policy_id;
6975 }
6976 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6977 if (cond_bound_interface) {
6978 ifnet_reference(cond_bound_interface);
6979 }
6980 new_kernel_policy->cond_bound_interface = cond_bound_interface;
6981 }
6982 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6983 new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6984 }
6985 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6986 new_kernel_policy->cond_protocol = cond_protocol;
6987 }
6988 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6989 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
6990 }
6991 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6992 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
6993 }
6994 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6995 new_kernel_policy->cond_local_prefix = cond_local_prefix;
6996 }
6997 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6998 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
6999 }
7000 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7001 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
7002 }
7003 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7004 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
7005 }
7006 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
7007 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
7008 }
7009 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7010 new_kernel_policy->cond_scheme_port = cond_scheme_port;
7011 }
7012 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
7013 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
7014 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
7015 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
7016 }
7017 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
7018 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
7019 }
7020
7021 new_kernel_policy->result = result;
7022 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
7023
7024 if (necp_debug) {
7025 NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
7026 }
7027 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
7028
7029 return new_kernel_policy ? new_kernel_policy->id : 0;
7030 }
7031
7032 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)7033 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
7034 {
7035 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7036 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7037
7038 if (policy_id == 0) {
7039 return NULL;
7040 }
7041
7042 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
7043 if (kernel_policy->id == policy_id) {
7044 return kernel_policy;
7045 }
7046 }
7047
7048 return NULL;
7049 }
7050
7051 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)7052 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
7053 {
7054 struct necp_kernel_ip_output_policy * __single policy = NULL;
7055
7056 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7057
7058 policy = necp_kernel_ip_output_policy_find(policy_id);
7059 if (policy) {
7060 LIST_REMOVE(policy, chain);
7061
7062 if (policy->cond_bound_interface) {
7063 ifnet_release(policy->cond_bound_interface);
7064 policy->cond_bound_interface = NULL;
7065 }
7066
7067 zfree(necp_ip_policy_zone, policy);
7068 return TRUE;
7069 }
7070
7071 return FALSE;
7072 }
7073
7074 static void
necp_kernel_ip_output_policies_dump_all(void)7075 necp_kernel_ip_output_policies_dump_all(void)
7076 {
7077 if (necp_debug) {
7078 struct necp_kernel_ip_output_policy *policy = NULL;
7079 int policy_i;
7080 int id_i;
7081 char result_string[MAX_RESULT_STRING_LEN];
7082 char proc_name_string[MAXCOMLEN + 1];
7083 memset(result_string, 0, MAX_RESULT_STRING_LEN);
7084 memset(proc_name_string, 0, MAXCOMLEN + 1);
7085
7086 NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
7087 NECPLOG0(LOG_DEBUG, "-----------\n");
7088 for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
7089 NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
7090 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++) {
7091 policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
7092 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
7093 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));
7094 }
7095 NECPLOG0(LOG_DEBUG, "-----------\n");
7096 }
7097 }
7098 }
7099
7100 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)7101 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
7102 {
7103 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7104 if (upper_policy->session_order != lower_policy->session_order) {
7105 // A skip cannot override a policy of a different session
7106 return FALSE;
7107 } else {
7108 if (upper_policy->result_parameter.skip_policy_order == 0 ||
7109 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
7110 // This policy is beyond the skip
7111 return FALSE;
7112 } else {
7113 // This policy is inside the skip
7114 return TRUE;
7115 }
7116 }
7117 }
7118
7119 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
7120 return TRUE;
7121 }
7122
7123 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)7124 necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy *policy, struct necp_kernel_ip_output_policy ** __indexable policy_array, int valid_indices)
7125 {
7126 bool can_skip = FALSE;
7127 u_int32_t highest_skip_session_order = 0;
7128 u_int32_t highest_skip_order = 0;
7129 int i;
7130 for (i = 0; i < valid_indices; i++) {
7131 struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
7132
7133 // For policies in a skip window, we can't mark conflicting policies as unnecessary
7134 if (can_skip) {
7135 if (highest_skip_session_order != compared_policy->session_order ||
7136 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
7137 // If we've moved on to the next session, or passed the skip window
7138 highest_skip_session_order = 0;
7139 highest_skip_order = 0;
7140 can_skip = FALSE;
7141 } else {
7142 // If this policy is also a skip, in can increase the skip window
7143 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7144 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
7145 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7146 }
7147 }
7148 continue;
7149 }
7150 }
7151
7152 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7153 // This policy is a skip. Set the skip window accordingly
7154 can_skip = TRUE;
7155 highest_skip_session_order = compared_policy->session_order;
7156 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7157 }
7158
7159 // The result of the compared policy must be able to block out this policy result
7160 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
7161 continue;
7162 }
7163
7164 // If new policy matches All Interfaces, compared policy must also
7165 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
7166 continue;
7167 }
7168
7169 // If new policy matches Local Networks, compared policy must also
7170 if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
7171 continue;
7172 }
7173
7174 // Default makes lower policies unnecessary always
7175 if (compared_policy->condition_mask == 0) {
7176 return TRUE;
7177 }
7178
7179 // Compared must be more general than policy, and include only conditions within policy
7180 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
7181 continue;
7182 }
7183
7184 // Negative conditions must match for the overlapping conditions
7185 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
7186 continue;
7187 }
7188
7189 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
7190 compared_policy->cond_policy_id != policy->cond_policy_id) {
7191 continue;
7192 }
7193
7194 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
7195 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
7196 continue;
7197 }
7198
7199 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
7200 compared_policy->cond_protocol != policy->cond_protocol) {
7201 continue;
7202 }
7203
7204 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7205 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7206 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))) {
7207 continue;
7208 }
7209 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7210 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
7211 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
7212 continue;
7213 }
7214 }
7215 }
7216
7217 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7218 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7219 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))) {
7220 continue;
7221 }
7222 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7223 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
7224 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
7225 continue;
7226 }
7227 }
7228 }
7229
7230 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
7231 compared_policy->cond_scheme_port != policy->cond_scheme_port) {
7232 continue;
7233 }
7234
7235 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
7236 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
7237 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
7238 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
7239 continue;
7240 }
7241
7242 return TRUE;
7243 }
7244
7245 return FALSE;
7246 }
7247
7248 static bool
necp_kernel_ip_output_policies_reprocess(void)7249 necp_kernel_ip_output_policies_reprocess(void)
7250 {
7251 int i;
7252 int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
7253 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7254
7255 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7256
7257 // Reset mask to 0
7258 necp_kernel_ip_output_policies_condition_mask = 0;
7259 necp_kernel_ip_output_policies_count = 0;
7260 necp_kernel_ip_output_policies_non_id_count = 0;
7261
7262 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7263 if (necp_kernel_ip_output_policies_map[i] != NULL) {
7264 kfree_type(struct necp_kernel_ip_output_policy *,
7265 necp_kernel_ip_output_policies_map_counts[i] + 1,
7266 necp_kernel_ip_output_policies_map[i]);
7267 necp_kernel_ip_output_policies_map[i] = NULL;
7268 }
7269
7270 // Init counts
7271 necp_kernel_ip_output_policies_map_counts[i] = 0;
7272 }
7273
7274 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7275 // Update mask
7276 necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
7277 necp_kernel_ip_output_policies_count++;
7278
7279 /* Update bucket counts:
7280 * Non-id and SKIP policies will be added to all buckets
7281 * Add local networks policy to all buckets for incoming IP
7282 */
7283 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7284 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7285 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7286 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7287 necp_kernel_ip_output_policies_map_counts[i]++;
7288 }
7289 }
7290 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
7291 necp_kernel_ip_output_policies_non_id_count++;
7292 } else {
7293 necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
7294 }
7295 }
7296
7297 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7298 if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
7299 // Allocate a NULL-terminated array of policy pointers for each bucket
7300 necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
7301 necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
7302 if (necp_kernel_ip_output_policies_map[i] == NULL) {
7303 goto fail;
7304 }
7305 }
7306 bucket_current_free_index[i] = 0;
7307 }
7308
7309 u_int32_t current_session_order = 0;
7310 u_int32_t current_session_last_non_skip_policy = 0;
7311
7312 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7313 // For each new session, find the last non-skip policy. We can
7314 // avoid adding any skip policies that don't actually skip over
7315 // any non-skip policies.
7316 if (current_session_order != kernel_policy->session_order) {
7317 current_session_order = kernel_policy->session_order;
7318 current_session_last_non_skip_policy = 0;
7319
7320 struct necp_kernel_ip_output_policy *inner_policy = NULL;
7321 LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
7322 if (inner_policy->session_order < current_session_order) {
7323 continue;
7324 }
7325 if (inner_policy->session_order > current_session_order) {
7326 break;
7327 }
7328 if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7329 continue;
7330 }
7331
7332 current_session_last_non_skip_policy = inner_policy->order;
7333 }
7334 }
7335
7336 if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7337 if (current_session_last_non_skip_policy == 0) {
7338 // No useful policies to skip over, don't add
7339 continue;
7340 }
7341 if (kernel_policy->order >= current_session_last_non_skip_policy) {
7342 // Skip policy is after the last useful policy, don't add
7343 continue;
7344 }
7345 }
7346
7347 // Insert pointers into map
7348 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7349 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7350 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7351 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7352 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])) {
7353 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7354 bucket_current_free_index[i]++;
7355 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7356 }
7357 }
7358 } else {
7359 i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7360 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])) {
7361 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7362 bucket_current_free_index[i]++;
7363 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7364 }
7365 }
7366 }
7367
7368 if (bucket_current_free_index[0] == 0) {
7369 // No non-id policies were actually added
7370 necp_kernel_ip_output_policies_non_id_count = 0;
7371
7372 // Also check if no policies at all were added
7373 bool policies_added = FALSE;
7374 for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7375 if (bucket_current_free_index[i] != 0) {
7376 policies_added = TRUE;
7377 break;
7378 }
7379 }
7380 if (!policies_added) {
7381 necp_kernel_ip_output_policies_condition_mask = 0;
7382 necp_kernel_ip_output_policies_count = 0;
7383 }
7384 }
7385
7386 necp_kernel_ip_output_policies_dump_all();
7387 return TRUE;
7388
7389 fail:
7390 // Free memory, reset mask to 0
7391 necp_kernel_ip_output_policies_condition_mask = 0;
7392 necp_kernel_ip_output_policies_count = 0;
7393 necp_kernel_ip_output_policies_non_id_count = 0;
7394 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7395 if (necp_kernel_ip_output_policies_map[i] != NULL) {
7396 kfree_type(struct necp_kernel_ip_output_policy *,
7397 necp_kernel_ip_output_policies_map_counts[i] + 1,
7398 necp_kernel_ip_output_policies_map[i]);
7399 necp_kernel_ip_output_policies_map[i] = NULL;
7400 }
7401 }
7402 return FALSE;
7403 }
7404
7405 // Outbound Policy Matching
7406 // ---------------------
7407 struct substring {
7408 size_t length;
7409 char * __sized_by(length) string;
7410 };
7411
7412 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7413 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7414 {
7415 struct substring sub = {};
7416 char * __indexable ptr = string;
7417 size_t len = string ? length : 0;
7418
7419 while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7420 ptr++;
7421 len--;
7422 }
7423
7424 while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7425 len--;
7426 }
7427
7428 sub.string = ptr;
7429 sub.length = len;
7430 return sub;
7431 }
7432
7433 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7434 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7435 {
7436 size_t trimmed_domain_length = 0;
7437 char *trimmed_domain = NULL;
7438 struct substring sub = necp_trim_dots_and_stars(string, length);
7439
7440 trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7441 trimmed_domain_length = sub.length + 1;
7442 if (trimmed_domain == NULL) {
7443 return NULL;
7444 }
7445
7446 strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7447 trimmed_domain[sub.length] = 0;
7448
7449 return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7450 }
7451
7452 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7453 necp_count_dots(char * __sized_by(length)string, size_t length)
7454 {
7455 int dot_count = 0;
7456 size_t i = 0;
7457
7458 for (i = 0; i < length; i++) {
7459 if (string[i] == '.') {
7460 dot_count++;
7461 }
7462 }
7463
7464 return dot_count;
7465 }
7466
7467 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7468 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7469 {
7470 if (parent.length <= suffix.length) {
7471 return FALSE;
7472 }
7473
7474 size_t length_difference = (parent.length - suffix.length);
7475
7476 if (require_dot_before_suffix) {
7477 if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7478 return FALSE;
7479 }
7480 }
7481
7482 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7483 return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7484 }
7485
7486 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)7487 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7488 {
7489 if (hostname_substring.string == NULL || domain == NULL) {
7490 return hostname_substring.string == domain;
7491 }
7492
7493 struct substring domain_substring;
7494 domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7495 domain_substring.length = strlen(domain);
7496
7497 if (hostname_dot_count == domain_dot_count) {
7498 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7499 if (hostname_substring.length == domain_substring.length &&
7500 strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7501 return TRUE;
7502 }
7503 } else if (domain_dot_count < hostname_dot_count) {
7504 if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7505 return TRUE;
7506 }
7507 }
7508
7509 return FALSE;
7510 }
7511
7512 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7513 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7514 {
7515 if (hostname_string == NULL ||
7516 domain_string == NULL) {
7517 return false;
7518 }
7519
7520 struct substring hostname_substring;
7521 hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7522 hostname_substring.length = strlen(hostname_string);
7523
7524 return necp_hostname_matches_domain(hostname_substring,
7525 necp_count_dots(hostname_substring.string, hostname_substring.length),
7526 domain_string,
7527 necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7528 }
7529
7530 #define NECP_MAX_STRING_LEN 1024
7531
7532 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7533 necp_copy_string(char * __sized_by(length)string, size_t length)
7534 {
7535 size_t copied_string_length = 0;
7536 char * __sized_by(copied_string_length) copied_string = NULL;
7537
7538 if (length > NECP_MAX_STRING_LEN) {
7539 return NULL;
7540 }
7541
7542 copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7543 copied_string_length = length + 1;
7544 if (copied_string == NULL) {
7545 return NULL;
7546 }
7547
7548 memcpy(copied_string, string, length);
7549 copied_string[length] = 0;
7550
7551 return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7552 }
7553
7554 static u_int32_t
necp_get_primary_direct_interface_index(void)7555 necp_get_primary_direct_interface_index(void)
7556 {
7557 u_int32_t interface_index = IFSCOPE_NONE;
7558
7559 ifnet_head_lock_shared();
7560 struct ifnet *ordered_interface = NULL;
7561 TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7562 const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7563 if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7564 functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7565 // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7566 interface_index = ordered_interface->if_index;
7567 break;
7568 }
7569 }
7570 ifnet_head_done();
7571
7572 return interface_index;
7573 }
7574
7575 static inline bool
necp_task_has_match_entitlement(task_t task)7576 necp_task_has_match_entitlement(task_t task)
7577 {
7578 return task != NULL &&
7579 (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7580 IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7581 }
7582
7583 // Loopback traffic from certain entitled process will be dropped
7584 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7585 necp_task_has_loopback_drop_entitlement(task_t task)
7586 {
7587 bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7588 if (drop) {
7589 necp_drop_loopback_count++;
7590 }
7591 return drop;
7592 }
7593
7594 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7595 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7596 {
7597 coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7598
7599 if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7600 // No parent, nothing to do
7601 return;
7602 }
7603
7604 task_t __single lead_task = coalition_get_leader(coal);
7605 if (lead_task != NULL) {
7606 info->is_entitled = necp_task_has_match_entitlement(lead_task);
7607 task_deallocate(lead_task);
7608 }
7609 }
7610
7611 // Some processes, due to particular entitlements, require using an NECP client to
7612 // access networking. Returns true if the result should be a Drop.
7613 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7614 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7615 {
7616 if (necp_is_platform_binary(proc)) {
7617 // This check is currently for the "on-demand-install-capable"
7618 // entitlement, which by definition cannot be a built-in platform
7619 // binary.
7620 return false;
7621 }
7622
7623 task_t __single task = proc_task(proc ? proc : current_proc());
7624
7625 if (!info->has_client &&
7626 task != NULL &&
7627 IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7628 // Drop connections that don't use NECP clients and have the
7629 // com.apple.developer.on-demand-install-capable entitlement.
7630 // This effectively restricts those processes to only using
7631 // an NECP-aware path for networking.
7632 return true;
7633 } else {
7634 return false;
7635 }
7636 }
7637
7638 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7639 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7640 {
7641 if (!necp_restrict_multicast || proc == NULL) {
7642 return false;
7643 }
7644
7645 // Check for multicast/broadcast here
7646 if (info->remote_addr.sa.sa_family == AF_INET) {
7647 if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7648 info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7649 return false;
7650 }
7651 } else if (info->remote_addr.sa.sa_family == AF_INET6) {
7652 if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7653 return false;
7654 }
7655 } else {
7656 // Not IPv4/IPv6
7657 return false;
7658 }
7659
7660 if (necp_is_platform_binary(proc)) {
7661 return false;
7662 }
7663
7664 const uint32_t platform = proc_platform(proc);
7665 const uint32_t sdk = proc_sdk(proc);
7666
7667 // Enforce for iOS, linked on or after version 14
7668 // If the caller set `check_minor_version`, only enforce starting at 14.5
7669 if ((platform != PLATFORM_IOS ||
7670 sdk == 0 ||
7671 (sdk >> 16) < 14 ||
7672 (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7673 return false;
7674 }
7675
7676 // Allow entitled processes to use multicast
7677 task_t __single task = proc_task(proc);
7678 if (task != NULL &&
7679 IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7680 return false;
7681 }
7682
7683 const uint32_t min_sdk = proc_min_sdk(proc);
7684 NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7685
7686 return true;
7687 }
7688
7689 #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)
7690 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)7691 necp_application_fillout_info_locked(task_t task, uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account __null_terminated, char *domain __null_terminated, char *url __null_terminated, pid_t pid, int32_t pid_version, uid_t uid, uid_t real_uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, union necp_sockaddr_union *local_addr, union necp_sockaddr_union *remote_addr, u_int16_t local_port, u_int16_t remote_port, bool has_client, bool has_system_signed_result, proc_t real_proc, proc_t proc, proc_t responsible_proc, u_int32_t drop_order, u_int32_t client_flags, u_int16_t scheme_port, struct necp_socket_info *info, bool is_loopback, bool is_delegated)
7692 {
7693 memset(info, 0, sizeof(struct necp_socket_info));
7694
7695 info->pid = pid;
7696 info->pid_version = pid_version;
7697 info->uid = uid;
7698 info->real_uid = real_uid;
7699 info->protocol = protocol;
7700 info->bound_interface_index = bound_interface_index;
7701 info->traffic_class = traffic_class;
7702 info->has_client = has_client;
7703 info->has_system_signed_result = has_system_signed_result;
7704 info->drop_order = drop_order;
7705 info->client_flags = client_flags;
7706 info->is_loopback = is_loopback;
7707 info->is_delegated = is_delegated;
7708
7709 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7710 info->bound_interface_index != IFSCOPE_NONE) {
7711 ifnet_head_lock_shared();
7712 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7713 if (interface != NULL) {
7714 info->bound_interface_flags = interface->if_flags;
7715 info->bound_interface_eflags = interface->if_eflags;
7716 info->bound_interface_xflags = interface->if_xflags;
7717 }
7718 ifnet_head_done();
7719 }
7720
7721 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7722 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7723 if (existing_mapping) {
7724 info->application_id = existing_mapping->id;
7725 }
7726 }
7727
7728 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7729 if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7730 info->real_application_id = info->application_id;
7731 } else {
7732 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7733 if (existing_mapping) {
7734 info->real_application_id = existing_mapping->id;
7735 }
7736 }
7737 }
7738
7739 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7740 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7741 if (existing_mapping != NULL) {
7742 info->real_application_id = info->application_id;
7743 info->application_id = existing_mapping->id;
7744 info->used_responsible_pid = true;
7745 }
7746 }
7747
7748 if (info->used_responsible_pid) {
7749 proc = responsible_proc;
7750 }
7751
7752 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7753 info->is_entitled = necp_task_has_match_entitlement(task);
7754 if (!info->is_entitled) {
7755 // Task does not have entitlement, check the parent task
7756 necp_get_parent_is_entitled(task, info);
7757 }
7758 }
7759
7760 if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7761 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7762 if (necp_is_platform_binary(proc)) {
7763 info->is_platform_binary = true;
7764 } else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7765 info->is_platform_binary = true;
7766 info->used_responsible_pid = true;
7767 } else {
7768 info->is_platform_binary = false;
7769 }
7770 }
7771
7772 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7773 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7774 }
7775
7776 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7777 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7778 if (existing_mapping) {
7779 info->account_id = existing_mapping->id;
7780 }
7781 }
7782
7783 if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7784 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7785 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7786 info->domain = domain;
7787 }
7788
7789 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7790 info->url = url;
7791 }
7792
7793 if ((necp_data_tracing_level && necp_data_tracing_port) ||
7794 necp_restrict_multicast ||
7795 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7796 if (local_addr && local_addr->sa.sa_len > 0) {
7797 SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7798 if (local_port != 0) {
7799 info->local_addr.sin6.sin6_port = local_port;
7800 }
7801 } else {
7802 if (remote_addr && remote_addr->sa.sa_len > 0) {
7803 info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7804 info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7805 } else {
7806 info->local_addr.sin6.sin6_family = AF_INET6;
7807 info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7808 }
7809 if (local_port != 0) {
7810 info->local_addr.sin6.sin6_port = local_port;
7811 }
7812 }
7813 if (remote_addr && remote_addr->sa.sa_len > 0) {
7814 SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7815 if (remote_port != 0) {
7816 info->remote_addr.sin6.sin6_port = remote_port;
7817 }
7818 } else if (remote_port != 0) {
7819 info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7820 info->remote_addr.sin6.sin6_family = AF_INET6;
7821 info->remote_addr.sin6.sin6_port = remote_port;
7822 }
7823 }
7824
7825 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7826 info->scheme_port = scheme_port;
7827 }
7828 }
7829
7830 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7831 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7832 {
7833 struct kev_netpolicy_ifdenied ev_ifdenied;
7834
7835 bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7836
7837 ev_ifdenied.ev_data.epid = pid;
7838 uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7839 ev_ifdenied.ev_if_functional_type = if_functional_type;
7840
7841 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7842 }
7843
7844 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7845 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7846 {
7847 struct kev_netpolicy_netdenied ev_netdenied = {};
7848
7849 bzero(&ev_netdenied, sizeof(ev_netdenied));
7850
7851 ev_netdenied.ev_data.epid = pid;
7852 uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7853 ev_netdenied.ev_network_type = network_type;
7854
7855 netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7856 }
7857
7858 extern char *proc_name_address(void *p);
7859
7860 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7861 if (!has_checked_delegation_entitlement) { \
7862 has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7863 has_checked_delegation_entitlement = TRUE; \
7864 } \
7865 if (!has_delegation_entitlement) { \
7866 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7867 proc_name_address(_p), proc_pid(_p), _d); \
7868 break; \
7869 }
7870
7871 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)7872 necp_application_find_policy_match_internal(proc_t proc,
7873 u_int8_t * __sized_by(parameters_size)parameters,
7874 u_int32_t parameters_size,
7875 struct necp_aggregate_result *returned_result,
7876 u_int32_t *flags,
7877 u_int32_t *reason,
7878 u_int required_interface_index,
7879 const union necp_sockaddr_union *override_local_addr,
7880 const union necp_sockaddr_union *override_remote_addr,
7881 struct necp_client_endpoint *returned_v4_gateway,
7882 struct necp_client_endpoint *returned_v6_gateway,
7883 struct rtentry **returned_route, bool ignore_address,
7884 bool has_client,
7885 uuid_t *returned_override_euuid)
7886 {
7887 int error = 0;
7888 size_t offset = 0;
7889
7890 struct necp_kernel_socket_policy *matched_policy = NULL;
7891 struct necp_socket_info info = {};
7892 necp_kernel_policy_filter filter_control_unit = 0;
7893 necp_kernel_policy_result service_action = 0;
7894 necp_kernel_policy_service service = { 0, 0 };
7895
7896 u_int16_t protocol = 0;
7897 u_int32_t bound_interface_index = required_interface_index;
7898 u_int32_t traffic_class = 0;
7899 u_int32_t client_flags = 0;
7900 u_int16_t scheme_port = 0;
7901 union necp_sockaddr_union local_addr;
7902 union necp_sockaddr_union remote_addr;
7903 bool no_remote_addr = FALSE;
7904 u_int8_t remote_family = 0;
7905 bool no_local_addr = FALSE;
7906 u_int16_t local_port = 0;
7907 u_int16_t remote_port = 0;
7908 u_int32_t remote_endpoint_type = 0;
7909 bool remote_address_is_empty = false;
7910 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7911 bool is_delegated = false;
7912
7913 if (override_local_addr) {
7914 memcpy(&local_addr, override_local_addr, sizeof(local_addr));
7915 } else {
7916 memset(&local_addr, 0, sizeof(local_addr));
7917 }
7918 if (override_remote_addr) {
7919 memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
7920 } else {
7921 memset(&remote_addr, 0, sizeof(remote_addr));
7922 }
7923
7924 // Initialize UID, PID, and UUIDs to the current process
7925 uid_t uid = 0;
7926 uid_t real_uid = 0;
7927 kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
7928 if (cred != NULL) {
7929 uid = kauth_cred_getuid(cred);
7930 real_uid = uid;
7931 }
7932 task_t __single task = proc_task(proc);
7933 pid_t pid = proc_pid(proc);
7934 int32_t pid_version = proc_pidversion(proc);
7935 uuid_t application_uuid;
7936 uuid_clear(application_uuid);
7937 uuid_t real_application_uuid;
7938 uuid_clear(real_application_uuid);
7939 proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
7940 uuid_copy(application_uuid, real_application_uuid);
7941 uuid_t responsible_application_uuid;
7942 uuid_clear(responsible_application_uuid);
7943
7944 char *domain __null_terminated = NULL;
7945 char *url __null_terminated = NULL;
7946 char *account __null_terminated = NULL;
7947
7948 #define NECP_MAX_REQUIRED_AGENTS 16
7949 u_int32_t num_required_agent_types = 0;
7950 struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
7951 memset(&required_agent_types, 0, sizeof(required_agent_types));
7952
7953 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
7954 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
7955 memset(&netagent_ids, 0, sizeof(netagent_ids));
7956 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
7957 int netagent_cursor;
7958
7959 bool has_checked_delegation_entitlement = false;
7960 bool has_delegation_entitlement = false;
7961 bool has_system_signed_result = false;
7962
7963 proc_t responsible_proc = PROC_NULL;
7964 proc_t effective_proc = proc;
7965 bool release_eproc = false;
7966 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
7967
7968 u_int32_t flow_divert_aggregate_unit = 0;
7969
7970 if (returned_result == NULL) {
7971 if (cred != NULL) {
7972 kauth_cred_unref(&cred);
7973 }
7974 return EINVAL;
7975 }
7976
7977 if (returned_v4_gateway != NULL) {
7978 memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
7979 }
7980
7981 if (returned_v6_gateway != NULL) {
7982 memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
7983 }
7984
7985 if (returned_override_euuid != NULL) {
7986 uuid_clear(*returned_override_euuid);
7987 }
7988
7989 memset(returned_result, 0, sizeof(struct necp_aggregate_result));
7990
7991 u_int32_t drop_order = necp_process_drop_order(cred);
7992
7993 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
7994
7995 lck_rw_lock_shared(&necp_kernel_policy_lock);
7996 if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
7997 if (necp_drop_all_order > 0 || drop_order > 0) {
7998 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7999 lck_rw_done(&necp_kernel_policy_lock);
8000 if (cred != NULL) {
8001 kauth_cred_unref(&cred);
8002 }
8003 return 0;
8004 }
8005 }
8006 lck_rw_done(&necp_kernel_policy_lock);
8007
8008 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
8009 u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
8010 u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
8011
8012 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
8013 // If the length is larger than what can fit in the remaining parameters size, bail
8014 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
8015 break;
8016 }
8017
8018 if (length > 0) {
8019 u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
8020 if (value != NULL) {
8021 switch (type) {
8022 case NECP_CLIENT_PARAMETER_APPLICATION: {
8023 if (length >= sizeof(uuid_t)) {
8024 if (uuid_compare(application_uuid, value) == 0) {
8025 // No delegation
8026 break;
8027 }
8028
8029 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
8030
8031 is_delegated = true;
8032 uuid_copy(application_uuid, value);
8033 }
8034 break;
8035 }
8036 case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
8037 if (length >= sizeof(uuid_t)) {
8038 if (uuid_compare(real_application_uuid, value) == 0) {
8039 // No delegation
8040 break;
8041 }
8042
8043 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
8044
8045 is_delegated = true;
8046 uuid_copy(real_application_uuid, value);
8047 }
8048 break;
8049 }
8050 case NECP_CLIENT_PARAMETER_PID: {
8051 if (length >= sizeof(pid_t)) {
8052 if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
8053 // No delegation
8054 break;
8055 }
8056
8057 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
8058
8059 is_delegated = true;
8060 memcpy(&pid, value, sizeof(pid_t));
8061 }
8062 break;
8063 }
8064 case NECP_CLIENT_PARAMETER_UID: {
8065 if (length >= sizeof(uid_t)) {
8066 if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
8067 // No delegation
8068 break;
8069 }
8070
8071 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
8072
8073 is_delegated = true;
8074 memcpy(&uid, value, sizeof(uid_t));
8075 }
8076 break;
8077 }
8078 case NECP_CLIENT_PARAMETER_DOMAIN: {
8079 char *ptr = (char *)value;
8080 ptr[length - 1] = 0;
8081 domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8082 break;
8083 }
8084 case NECP_CLIENT_PARAMETER_URL: {
8085 char *ptr = (char *)value;
8086 ptr[length - 1] = 0;
8087 url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8088 break;
8089 }
8090 case NECP_CLIENT_PARAMETER_ACCOUNT: {
8091 char *ptr = (char *)value;
8092 ptr[length - 1] = 0;
8093 account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8094 break;
8095 }
8096 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
8097 if (length >= sizeof(u_int32_t)) {
8098 memcpy(&traffic_class, value, sizeof(u_int32_t));
8099 }
8100 break;
8101 }
8102 case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
8103 if (length >= sizeof(u_int16_t)) {
8104 memcpy(&protocol, value, sizeof(u_int16_t));
8105 } else if (length >= sizeof(u_int8_t)) {
8106 memcpy(&protocol, value, sizeof(u_int8_t));
8107 }
8108 break;
8109 }
8110 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
8111 if (length <= IFXNAMSIZ && length > 0) {
8112 ifnet_t __single bound_interface = NULL;
8113 char interface_name[IFXNAMSIZ];
8114 memcpy(interface_name, value, length);
8115 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
8116 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
8117 bound_interface_index = bound_interface->if_index;
8118 ifnet_release(bound_interface);
8119 }
8120 }
8121 break;
8122 }
8123 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
8124 if (ignore_address || override_local_addr) {
8125 break;
8126 }
8127
8128 if (length >= sizeof(struct necp_policy_condition_addr)) {
8129 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8130 if (necp_address_is_valid(&address_struct->address.sa)) {
8131 memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
8132 }
8133 }
8134 break;
8135 }
8136 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
8137 if (ignore_address || override_remote_addr) {
8138 break;
8139 }
8140
8141 if (length >= sizeof(struct necp_policy_condition_addr)) {
8142 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8143 if (necp_address_is_valid(&address_struct->address.sa)) {
8144 memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
8145 }
8146 }
8147 break;
8148 }
8149 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
8150 if (ignore_address || override_local_addr) {
8151 break;
8152 }
8153
8154 if (length >= sizeof(struct necp_client_endpoint)) {
8155 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8156 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
8157 endpoint->u.endpoint.endpoint_port != 0) {
8158 // Save port
8159 local_port = endpoint->u.endpoint.endpoint_port;
8160 }
8161 }
8162 break;
8163 }
8164 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
8165 if (ignore_address || override_remote_addr) {
8166 break;
8167 }
8168
8169 if (length >= sizeof(struct necp_client_endpoint)) {
8170 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8171 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
8172 remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
8173 if (endpoint->u.endpoint.endpoint_port != 0) {
8174 // Save port
8175 remote_port = endpoint->u.endpoint.endpoint_port;
8176 }
8177 } else if (necp_addr_is_empty(&endpoint->u.sa)) {
8178 remote_address_is_empty = true;
8179 }
8180 }
8181 break;
8182 }
8183 case NECP_CLIENT_PARAMETER_FLAGS: {
8184 if (length >= sizeof(client_flags)) {
8185 memcpy(&client_flags, value, sizeof(client_flags));
8186 }
8187 break;
8188 }
8189 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
8190 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
8191 if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8192 break;
8193 }
8194 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
8195 memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
8196 num_required_agent_types++;
8197 }
8198 break;
8199 }
8200 case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
8201 if (length >= sizeof(scheme_port)) {
8202 memcpy(&scheme_port, value, sizeof(scheme_port));
8203 }
8204 break;
8205 }
8206 case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
8207 has_system_signed_result = true;
8208 struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
8209 if (length >= sizeof(struct necp_client_validatable)) {
8210 // Check for system-signed sign_type values
8211 if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
8212 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
8213 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
8214 has_system_signed_result = true;
8215 }
8216 }
8217 break;
8218 }
8219 default: {
8220 break;
8221 }
8222 }
8223 }
8224 }
8225
8226 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
8227 }
8228
8229 // Check for loopback exception
8230 if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
8231 if (necp_task_has_loopback_drop_entitlement(task)) {
8232 // Disallow certain entitled processes to send loopback traffic
8233 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8234 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8235 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8236 if (cred != NULL) {
8237 kauth_cred_unref(&cred);
8238 }
8239 return 0;
8240 }
8241 if (necp_pass_loopback > 0) {
8242 bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
8243 }
8244 } else if (bound_interface_index != IFSCOPE_NONE) {
8245 // Check for inter-process exception
8246 struct sockaddr *dst = SA(&remote_addr.sa);
8247 if (dst->sa_family == AF_INET6) {
8248 struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
8249 if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
8250 ifnet_head_lock_shared();
8251 ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
8252 if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
8253 bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
8254 }
8255 ifnet_head_done();
8256 }
8257 }
8258 }
8259
8260 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
8261 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8262 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8263 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8264 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
8265 returned_result->routed_interface_index = lo_ifp->if_index;
8266 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8267 } else {
8268 returned_result->routed_interface_index = bound_interface_index;
8269 }
8270 if (cred != NULL) {
8271 kauth_cred_unref(&cred);
8272 }
8273 return 0;
8274 }
8275
8276 if (drop_order != 0) {
8277 if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
8278 client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
8279 ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
8280 // Allow listeners, inbound connections without remote addresses, and
8281 // application service connections to bypass the unentitled drop order,
8282 // to allow them to connect to application services (not directly over
8283 // physical networking interfaces)
8284 drop_order = 0;
8285 }
8286 }
8287
8288 if (proc_pid(effective_proc) != pid) {
8289 proc_t found_proc = proc_find(pid);
8290 if (found_proc != PROC_NULL) {
8291 effective_proc = found_proc;
8292 pid_version = proc_pidversion(effective_proc);
8293 release_eproc = true;
8294 }
8295 }
8296 #if defined(XNU_TARGET_OS_OSX)
8297 if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
8298 proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
8299 responsible_proc = proc_find(effective_proc->p_responsible_pid);
8300 }
8301 #endif /* defined(XNU_TARGET_OS_OSX) */
8302
8303 // Lock
8304 lck_rw_lock_shared(&necp_kernel_policy_lock);
8305
8306 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
8307 size_t route_rule_id_array_count = 0;
8308 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);
8309
8310 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
8311 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
8312
8313 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
8314 matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
8315 &info,
8316 &filter_control_unit,
8317 route_rule_id_array,
8318 &route_rule_id_array_count,
8319 MAX_AGGREGATE_ROUTE_RULES,
8320 &service_action,
8321 &service,
8322 netagent_ids,
8323 NECP_MAX_NETAGENTS,
8324 netagent_use_flags,
8325 NECP_MAX_NETAGENTS,
8326 required_agent_types,
8327 num_required_agent_types,
8328 info.used_responsible_pid ? responsible_proc : effective_proc,
8329 0,
8330 &skip_policy_id,
8331 NULL,
8332 &drop_dest_policy_result,
8333 &drop_all_bypass,
8334 &flow_divert_aggregate_unit,
8335 NULL,
8336 debug);
8337
8338 // Check for loopback exception again after the policy match
8339 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
8340 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
8341 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
8342 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8343 returned_result->filter_control_unit = 0;
8344 } else {
8345 returned_result->filter_control_unit = filter_control_unit;
8346 }
8347
8348 if (flow_divert_aggregate_unit > 0) {
8349 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8350 }
8351
8352 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8353 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8354 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8355 returned_result->routed_interface_index = lo_ifp->if_index;
8356 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8357 error = 0;
8358 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8359 goto done;
8360 }
8361
8362 if (matched_policy) {
8363 returned_result->policy_id = matched_policy->id;
8364 returned_result->skip_policy_id = skip_policy_id;
8365 returned_result->routing_result = matched_policy->result;
8366 memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8367 if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8368 uuid_copy(*returned_override_euuid, responsible_application_uuid);
8369 }
8370 } else {
8371 bool drop_all = false;
8372 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8373 // Mark socket as a drop if drop_all is set
8374 drop_all = true;
8375 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8376 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8377 }
8378 }
8379 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8380 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8381 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8382 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8383 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8384 } else {
8385 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8386 returned_result->skip_policy_id = skip_policy_id;
8387 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8388 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8389 }
8390 }
8391 if (necp_check_missing_client_drop(proc, &info) ||
8392 necp_check_restricted_multicast_drop(proc, &info, false)) {
8393 // Mark as drop
8394 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8395 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8396 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8397 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8398 }
8399 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8400 returned_result->filter_control_unit = 0;
8401 } else {
8402 returned_result->filter_control_unit = filter_control_unit;
8403 }
8404
8405 if (flow_divert_aggregate_unit > 0) {
8406 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8407 }
8408
8409 returned_result->service_action = service_action;
8410
8411 // Fetch service registration
8412 if (service.identifier != 0) {
8413 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
8414 if (mapping != NULL) {
8415 struct necp_service_registration *service_registration = NULL;
8416 uuid_copy(returned_result->service_uuid, mapping->uuid);
8417 returned_result->service_data = service.data;
8418 if (service.identifier == NECP_NULL_SERVICE_ID) {
8419 // NULL service is always 'registered'
8420 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8421 } else {
8422 LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
8423 if (service.identifier == service_registration->service_id) {
8424 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8425 break;
8426 }
8427 }
8428 }
8429 }
8430 }
8431
8432 // Handle netagents
8433 size_t netagent_i = 0;
8434 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8435 struct necp_uuid_id_mapping *mapping = NULL;
8436 u_int32_t netagent_id = netagent_ids[netagent_cursor];
8437 if (netagent_id == 0) {
8438 continue;
8439 }
8440 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8441 if (mapping != NULL) {
8442 uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8443 returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8444 netagent_i++;
8445 }
8446
8447 // If the flags say to remove, clear the local copy
8448 if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8449 netagent_ids[netagent_cursor] = 0;
8450 }
8451 }
8452
8453 // Do routing evaluation
8454 u_int output_bound_interface = bound_interface_index;
8455 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8456 output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8457 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8458 output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8459 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8460 output_bound_interface = necp_get_primary_direct_interface_index();
8461 if (output_bound_interface == IFSCOPE_NONE) {
8462 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8463 } else {
8464 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8465 returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8466 }
8467 }
8468
8469 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8470 returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8471 if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8472 // Trigger the event that we dropped due to a local network policy
8473 #if defined(XNU_TARGET_OS_OSX)
8474 bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8475 necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8476 should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8477 NETPOLICY_NETWORKTYPE_LOCAL);
8478 #else
8479 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8480 #endif
8481 }
8482 if (reason != NULL) {
8483 *reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8484 }
8485 }
8486
8487 if (local_addr.sa.sa_len == 0 ||
8488 (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8489 (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8490 no_local_addr = TRUE;
8491 }
8492
8493 if (remote_addr.sa.sa_len == 0 ||
8494 (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8495 (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8496 no_remote_addr = TRUE;
8497 remote_family = remote_addr.sa.sa_family;
8498 }
8499
8500 returned_result->routed_interface_index = 0;
8501 struct rtentry *rt = NULL;
8502 if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8503 // Treat the output bound interface as the routed interface for local address
8504 // validation later.
8505 returned_result->routed_interface_index = output_bound_interface;
8506 } else {
8507 if (no_remote_addr) {
8508 memset(&remote_addr, 0, sizeof(remote_addr));
8509 if (remote_family == AF_INET6) {
8510 // Reset address to ::
8511 remote_addr.sa.sa_family = AF_INET6;
8512 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8513 } else {
8514 // Reset address to 0.0.0.0
8515 remote_addr.sa.sa_family = AF_INET;
8516 remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8517 }
8518 }
8519
8520 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8521 output_bound_interface);
8522
8523 if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8524 IS_INTF_CLAT46(rt->rt_ifp)) {
8525 rtfree(rt);
8526 rt = NULL;
8527 returned_result->routed_interface_index = 0;
8528 }
8529
8530 if (no_remote_addr && remote_family == AF_UNSPEC &&
8531 (rt == NULL || rt->rt_ifp == NULL)) {
8532 // Route lookup for default IPv4 failed, try IPv6
8533
8534 // Cleanup old route if necessary
8535 if (rt != NULL) {
8536 rtfree(rt);
8537 rt = NULL;
8538 }
8539
8540 // Reset address to ::
8541 memset(&remote_addr, 0, sizeof(remote_addr));
8542 remote_addr.sa.sa_family = AF_INET6;
8543 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8544
8545 // Get route
8546 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8547 output_bound_interface);
8548 }
8549
8550 if (rt != NULL &&
8551 rt->rt_ifp != NULL) {
8552 returned_result->routed_interface_index = rt->rt_ifp->if_index;
8553 /*
8554 * For local addresses, we allow the interface scope to be
8555 * either the loopback interface or the interface hosting the
8556 * local address.
8557 */
8558 if (bound_interface_index != IFSCOPE_NONE &&
8559 rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8560 (output_bound_interface == lo_ifp->if_index ||
8561 rt->rt_ifp->if_index == lo_ifp->if_index ||
8562 rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8563 struct sockaddr_storage dst;
8564 unsigned int ifscope = bound_interface_index;
8565
8566 /*
8567 * Transform dst into the internal routing table form
8568 */
8569 (void) sa_copy(SA(&remote_addr),
8570 &dst, &ifscope);
8571
8572 if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8573 rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8574 returned_result->routed_interface_index =
8575 bound_interface_index;
8576 }
8577 }
8578 }
8579 }
8580
8581 if (returned_result->routed_interface_index != 0 &&
8582 returned_result->routed_interface_index != lo_ifp->if_index && // Loopback can accept any local address
8583 !no_local_addr) {
8584 // Transform local_addr into the ifaddr form
8585 // IPv6 Scope IDs are always embedded in the ifaddr list
8586 struct sockaddr_storage local_address_sanitized;
8587 u_int ifscope = IFSCOPE_NONE;
8588 (void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8589 SIN(&local_address_sanitized)->sin_port = 0;
8590 if (local_address_sanitized.ss_family == AF_INET6) {
8591 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8592 SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8593 }
8594 }
8595
8596 // Validate local address on routed interface
8597 struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8598 if (ifa == NULL) {
8599 // Interface address not found, reject route
8600 returned_result->routed_interface_index = 0;
8601 if (rt != NULL) {
8602 rtfree(rt);
8603 rt = NULL;
8604 }
8605 } else {
8606 ifaddr_release(ifa);
8607 ifa = NULL;
8608 }
8609 }
8610
8611 if (flags != NULL) {
8612 #if SKYWALK
8613 if (kernel_is_macos_or_server()) {
8614 enum net_filter_event_subsystems filters = net_filter_event_get_state();
8615
8616 if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8617 *flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8618 }
8619 if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8620 *flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8621 }
8622 if (filters & NET_FILTER_EVENT_ALF) {
8623 *flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8624 }
8625 if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8626 *flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8627 }
8628 }
8629 #endif /* SKYWALK */
8630 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8631 // Check for local/direct
8632 bool is_local = FALSE;
8633 if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8634 is_local = TRUE;
8635 } else if (returned_result->routed_interface_index != 0 &&
8636 !no_remote_addr) {
8637 // Clean up the address before comparison with interface addresses
8638
8639 // Transform remote_addr into the ifaddr form
8640 // IPv6 Scope IDs are always embedded in the ifaddr list
8641 struct sockaddr_storage remote_address_sanitized;
8642 u_int ifscope = IFSCOPE_NONE;
8643 (void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8644 SIN(&remote_address_sanitized)->sin_port = 0;
8645 if (remote_address_sanitized.ss_family == AF_INET6) {
8646 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8647 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8648 }
8649 }
8650
8651 // Check if remote address is an interface address
8652 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8653 if (ifa != NULL && ifa->ifa_ifp != NULL) {
8654 u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8655 if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8656 if_index_for_remote_addr == lo_ifp->if_index) {
8657 is_local = TRUE;
8658 }
8659 }
8660 if (ifa != NULL) {
8661 ifaddr_release(ifa);
8662 ifa = NULL;
8663 }
8664 }
8665
8666 if (is_local) {
8667 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8668 } else if (rt != NULL) {
8669 if (rt->rt_flags & RTF_GLOBAL) {
8670 *flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8671 } else if (!(rt->rt_flags & RTF_GATEWAY) &&
8672 (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8673 // Route is directly accessible
8674 *flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8675 }
8676 }
8677
8678 if (rt != NULL &&
8679 rt->rt_ifp != NULL) {
8680 // Check probe status
8681 if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8682 *flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8683 }
8684
8685 if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8686 struct if_cellular_status_v1 *ifsr;
8687
8688 ifnet_lock_shared(rt->rt_ifp);
8689 lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8690
8691 if (rt->rt_ifp->if_link_status != NULL) {
8692 ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8693
8694 if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8695 if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8696 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8697 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8698 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8699 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8700 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8701 }
8702 }
8703 }
8704 lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8705 ifnet_lock_done(rt->rt_ifp);
8706 }
8707
8708 // Check link quality
8709 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8710 (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8711 rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8712 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8713 }
8714
8715 // Check QoS marking (fastlane)
8716 for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8717 if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8718 *flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8719 // If the route can use QoS markings, stop iterating route rules
8720 break;
8721 }
8722 }
8723
8724 if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8725 *flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8726 }
8727
8728 if (traffic_class == SO_TC_BK_SYS) {
8729 // Block BK_SYS traffic if interface is throttled
8730 u_int32_t throttle_level = 0;
8731 if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8732 if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8733 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8734 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8735 }
8736 }
8737 }
8738 }
8739 }
8740
8741 u_int interface_to_check = returned_result->routed_interface_index;
8742 if (interface_to_check == 0) {
8743 interface_to_check = output_bound_interface;
8744 }
8745 union necp_sockaddr_union default_address;
8746 struct rtentry *v4Route = NULL;
8747 struct rtentry *v6Route = NULL;
8748
8749 memset(&default_address, 0, sizeof(default_address));
8750
8751 // Reset address to 0.0.0.0
8752 default_address.sa.sa_family = AF_INET;
8753 default_address.sa.sa_len = sizeof(struct sockaddr_in);
8754 v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8755 returned_result->routed_interface_index);
8756
8757 // Reset address to ::
8758 default_address.sa.sa_family = AF_INET6;
8759 default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8760 v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8761 returned_result->routed_interface_index);
8762
8763 if (v4Route != NULL) {
8764 if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8765 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8766 }
8767 if (returned_v4_gateway != NULL &&
8768 v4Route->rt_gateway != NULL &&
8769 v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8770 memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8771 memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8772 }
8773 rtfree(v4Route);
8774 v4Route = NULL;
8775 }
8776
8777 if (v6Route != NULL) {
8778 if (v6Route->rt_ifp != NULL) {
8779 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8780
8781 if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8782 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8783 }
8784 }
8785 if (returned_v6_gateway != NULL &&
8786 v6Route->rt_gateway != NULL &&
8787 v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8788 SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8789 }
8790 rtfree(v6Route);
8791 v6Route = NULL;
8792 }
8793 }
8794
8795 // Take two passes through the rule list: first for rules that don't match based on agents,
8796 // second for rules that match based on agents. Since rules can modify the agent list itself,
8797 // this makes the logic more deterministic. This allows a non-agent matching rule to remove
8798 // an agent before it is used for matching later.
8799 size_t route_rule_index = 0;
8800 bool second_pass = false;
8801 while (route_rule_index < route_rule_id_array_count) {
8802 bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8803 if (rule_matches_agents != second_pass) {
8804 // Process rules that match based on agents only in the second pass
8805 route_rule_index++;
8806 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8807 route_rule_index = 0;
8808 second_pass = true;
8809 }
8810 continue;
8811 }
8812
8813 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8814 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);
8815 if (!route_is_allowed) {
8816 // If the route is blocked, treat the lookup as a drop
8817 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8818 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8819
8820 if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8821 if (reason != NULL) {
8822 if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8823 *reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8824 } else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8825 *reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8826 }
8827 }
8828 necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8829 }
8830 // If the route gets denied, stop matching rules
8831 break;
8832 }
8833
8834 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8835 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8836 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8837 route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8838 if (flow_divert_control_unit != 0) {
8839 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8840 returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8841 }
8842 if (flow_divert_aggregate_unit != 0) {
8843 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8844 }
8845 }
8846
8847 // Check if there is a route rule that adds or removes an agent
8848 bool remove = false;
8849 u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8850 if (netagent_id != 0) {
8851 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8852 if (mapping != NULL) {
8853 bool agent_already_present = false;
8854 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8855 if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8856 // Found the agent already present
8857 agent_already_present = true;
8858 if (remove) {
8859 // Mark as remove if necessary
8860 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8861 }
8862 } else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8863 // Found open slot
8864 if (!agent_already_present) {
8865 uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8866 if (remove) {
8867 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8868 } else {
8869 returned_result->netagent_use_flags[netagent_cursor] = 0;
8870 }
8871 }
8872 break;
8873 }
8874 }
8875 }
8876
8877 // Update the local netagent_ids array for future evaluations
8878 if (remove) {
8879 // Check if the agent ID is in the array, and remove it
8880 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8881 if (netagent_id == netagent_ids[netagent_cursor]) {
8882 netagent_ids[netagent_cursor] = 0;
8883 }
8884 }
8885 } else {
8886 // Check if the agent ID is not yet in the array, and add it
8887 bool found = false;
8888 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8889 if (netagent_id == netagent_ids[netagent_cursor]) {
8890 found = true;
8891 break;
8892 }
8893 }
8894 if (!found) {
8895 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8896 if (netagent_ids[netagent_cursor] == 0) {
8897 // Empty slot, add the agent
8898 netagent_ids[netagent_cursor] = netagent_id;
8899 break;
8900 }
8901 }
8902 }
8903 }
8904 }
8905
8906 route_rule_index++;
8907 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8908 route_rule_index = 0;
8909 second_pass = true;
8910 }
8911 }
8912
8913 if (rt != NULL && rt->rt_ifp != NULL) {
8914 const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8915 const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8916 const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8917 IFNET_IS_EXPENSIVE(rt->rt_ifp));
8918 const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8919 IFNET_IS_CONSTRAINED(rt->rt_ifp));
8920 const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
8921 IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
8922 !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT)));
8923
8924 const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
8925 if (!is_listener && !is_browser) {
8926 if (reason != NULL) {
8927 if (expensive_prohibited) {
8928 *reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8929 } else if (constrained_prohibited) {
8930 *reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8931 } else if (ultra_constrained_not_allowed) {
8932 *reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8933 }
8934 }
8935 if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
8936 // If a property of the interface was not allowed, treat it as a drop
8937 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8938 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8939 }
8940 }
8941 }
8942
8943 if (rt != NULL) {
8944 if (returned_route != NULL) {
8945 *returned_route = rt;
8946 } else {
8947 rtfree(rt);
8948 }
8949 rt = NULL;
8950 }
8951
8952 done:
8953 // Unlock
8954 lck_rw_done(&necp_kernel_policy_lock);
8955
8956 if (release_eproc && effective_proc != PROC_NULL) {
8957 proc_rele(effective_proc);
8958 }
8959 #if defined(XNU_TARGET_OS_OSX)
8960 if (responsible_proc != PROC_NULL) {
8961 proc_rele(responsible_proc);
8962 }
8963 #endif
8964
8965 if (cred != NULL) {
8966 kauth_cred_unref(&cred);
8967 }
8968
8969 return error;
8970 }
8971
8972 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)8973 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
8974 {
8975 struct rtentry *rt = NULL;
8976 bool is_local = FALSE;
8977
8978 if (remote_addr == NULL) {
8979 return NULL;
8980 }
8981
8982 if (remote_addr->sa.sa_len == 0 ||
8983 (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8984 (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8985 return FALSE;
8986 }
8987
8988 // Lookup route regardless of the scoped interface to check if
8989 // remote address is in a local network.
8990 rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
8991
8992 if (rt == NULL) {
8993 goto done;
8994 }
8995 if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
8996 goto free_rt;
8997 }
8998 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
8999
9000 free_rt:
9001 rtfree(rt);
9002
9003 done:
9004 return is_local;
9005 }
9006
9007 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)9008 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
9009 necp_app_id app_id,
9010 necp_app_id real_app_id,
9011 uint8_t is_entitled,
9012 u_int32_t account_id,
9013 struct substring domain,
9014 u_int8_t domain_dot_count,
9015 const char *url __null_terminated,
9016 pid_t pid,
9017 int32_t pid_version,
9018 uid_t uid,
9019 uid_t real_uid,
9020 u_int32_t bound_interface_index,
9021 u_int32_t traffic_class,
9022 u_int16_t protocol,
9023 union necp_sockaddr_union *local,
9024 union necp_sockaddr_union *remote,
9025 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9026 u_int32_t num_required_agent_types,
9027 bool has_client,
9028 uint32_t client_flags,
9029 int is_platform_binary,
9030 bool has_signed_result,
9031 proc_t proc,
9032 u_int16_t pf_tag,
9033 u_int16_t scheme_port,
9034 struct rtentry *rt,
9035 bool is_loopback,
9036 int debug,
9037 bool real_is_platform_binary,
9038 u_int32_t bound_interface_flags,
9039 u_int32_t bound_interface_eflags,
9040 u_int32_t bound_interface_xflags,
9041 struct necp_socket_info *info,
9042 bool is_delegated,
9043 struct socket *socket)
9044 {
9045 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9046 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9047 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9048 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9049 "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
9050 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9051 if (bound_interface_index == cond_bound_interface_index) {
9052 // No match, matches forbidden interface
9053 return FALSE;
9054 }
9055 } else {
9056 if (bound_interface_index != cond_bound_interface_index) {
9057 // No match, does not match required interface
9058 return FALSE;
9059 }
9060 }
9061 }
9062 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9063 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9064 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9065 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9066 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9067 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9068 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9069 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9070 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9071 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9072 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9073 // No match, matches some forbidden interface flags
9074 return FALSE;
9075 }
9076 } else {
9077 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9078 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9079 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9080 // No match, does not match some required interface xflags
9081 return FALSE;
9082 }
9083 }
9084 }
9085 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9086 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9087 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
9088 if (bound_interface_index != 0) {
9089 // No match, requires a non-bound packet
9090 return FALSE;
9091 }
9092 }
9093 }
9094
9095 if (kernel_policy->condition_mask == 0) {
9096 return TRUE;
9097 }
9098
9099 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9100 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
9101 "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
9102 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
9103 if (app_id == kernel_policy->cond_app_id) {
9104 // No match, matches forbidden application
9105 return FALSE;
9106 }
9107 } else {
9108 if (app_id != kernel_policy->cond_app_id) {
9109 // No match, does not match required application
9110 return FALSE;
9111 }
9112 }
9113
9114 // Check signing identifier only after APP ID matched
9115 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
9116 kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9117 u_int8_t matched = necp_boolean_state_false;
9118 const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
9119 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
9120 "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
9121 kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
9122 signing_id ? signing_id : "<n/a>");
9123 if (signing_id != NULL) {
9124 if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
9125 matched = necp_boolean_state_true;
9126 }
9127 }
9128
9129 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9130 if (matched == necp_boolean_state_true) {
9131 return FALSE;
9132 }
9133 } else {
9134 if (matched != necp_boolean_state_true) {
9135 return FALSE;
9136 }
9137 }
9138 }
9139 }
9140
9141 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9142 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
9143 "NECP_KERNEL_CONDITION_REAL_APP_ID",
9144 kernel_policy->cond_real_app_id, real_app_id);
9145 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9146 if (real_app_id == kernel_policy->cond_real_app_id) {
9147 // No match, matches forbidden application
9148 return FALSE;
9149 }
9150 } else {
9151 if (real_app_id != kernel_policy->cond_real_app_id) {
9152 // No match, does not match required application
9153 return FALSE;
9154 }
9155 }
9156 }
9157
9158 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9159 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
9160 if (!has_client) {
9161 return FALSE;
9162 }
9163 }
9164
9165 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9166 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
9167 if (!is_entitled) {
9168 // Process is missing entitlement
9169 return FALSE;
9170 }
9171 }
9172
9173 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9174 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);
9175 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9176 if (is_platform_binary) {
9177 // Process is platform binary
9178 return FALSE;
9179 }
9180 } else {
9181 if (!is_platform_binary) {
9182 // Process is not platform binary
9183 return FALSE;
9184 }
9185 }
9186 }
9187
9188 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9189 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
9190 if (has_signed_result == 0) {
9191 // Client did not have a system-signed result
9192 return FALSE;
9193 }
9194 }
9195
9196 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
9197 if (proc != NULL) {
9198 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
9199 kernel_policy->cond_sdk_version.platform,
9200 kernel_policy->cond_sdk_version.min_version,
9201 kernel_policy->cond_sdk_version.version,
9202 proc_platform(proc),
9203 proc_min_sdk(proc),
9204 proc_sdk(proc));
9205 if (kernel_policy->cond_sdk_version.platform != 0) {
9206 if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
9207 // Process does not match platform
9208 return FALSE;
9209 }
9210 }
9211
9212 if (kernel_policy->cond_sdk_version.min_version != 0) {
9213 if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
9214 // Process min version is older than required min version
9215 return FALSE;
9216 }
9217 }
9218
9219 if (kernel_policy->cond_sdk_version.version != 0) {
9220 if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
9221 // Process SDK version is older than required version
9222 return FALSE;
9223 }
9224 }
9225 }
9226 }
9227
9228 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
9229 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
9230 if (kernel_policy->cond_custom_entitlement != NULL) {
9231 if (proc == NULL) {
9232 // No process found, cannot check entitlement
9233 return FALSE;
9234 }
9235 task_t __single task = proc_task(proc);
9236 if (task == NULL ||
9237 !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
9238 // Process is missing custom entitlement
9239 return FALSE;
9240 }
9241 }
9242 }
9243
9244 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9245 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
9246 "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
9247 // Exact match requires the number of dots to match (no suffix matching allowed)
9248 bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
9249 necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
9250 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9251 if (domain_matches) {
9252 // No match, matches forbidden domain
9253 return FALSE;
9254 }
9255 } else {
9256 if (!domain_matches) {
9257 // No match, does not match required domain
9258 return FALSE;
9259 }
9260 }
9261 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9262 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
9263 "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
9264 bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
9265 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9266 if (domain_matches) {
9267 // No match, matches forbidden domain
9268 return FALSE;
9269 }
9270 } else {
9271 if (!domain_matches) {
9272 // No match, does not match required domain
9273 return FALSE;
9274 }
9275 }
9276 }
9277
9278 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9279 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9280 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (ID)", kernel_policy->cond_domain_filter, 0);
9281 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9282 "NECP_KERNEL_CONDITION_DOMAIN_FILTER (domain)", "<n/a>", domain.string);
9283 bool domain_matches = false;
9284 if (NECP_IS_DOMAIN_FILTER_ID(kernel_policy->cond_domain_filter)) {
9285 struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
9286 if (filter != NULL && filter->filter != NULL) {
9287 domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
9288 }
9289 } else {
9290 domain_matches = necp_match_domain_with_trie(&necp_global_domain_trie_list, kernel_policy->cond_domain_filter, domain.string, domain.length);
9291 if (debug) {
9292 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);
9293 }
9294 }
9295 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9296 if (domain_matches) {
9297 // No match, matches forbidden domain
9298 return FALSE;
9299 }
9300 } else {
9301 if (!domain_matches) {
9302 // No match, does not match required domain
9303 return FALSE;
9304 }
9305 }
9306 }
9307
9308 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
9309 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
9310 "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
9311 bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
9312 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
9313 if (url_matches) {
9314 // No match, matches forbidden url
9315 return FALSE;
9316 }
9317 } else {
9318 if (!url_matches) {
9319 // No match, does not match required url
9320 return FALSE;
9321 }
9322 }
9323 }
9324
9325 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9326 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
9327 "NECP_KERNEL_CONDITION_ACCOUNT_ID",
9328 kernel_policy->cond_account_id, account_id);
9329 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9330 if (account_id == kernel_policy->cond_account_id) {
9331 // No match, matches forbidden account
9332 return FALSE;
9333 }
9334 } else {
9335 if (account_id != kernel_policy->cond_account_id) {
9336 // No match, does not match required account
9337 return FALSE;
9338 }
9339 }
9340 }
9341
9342 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
9343 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
9344 "NECP_KERNEL_CONDITION_PID",
9345 kernel_policy->cond_pid, pid);
9346 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
9347 if (pid == kernel_policy->cond_pid) {
9348 // No match, matches forbidden pid
9349 return FALSE;
9350 }
9351 if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
9352 return FALSE;
9353 }
9354 } else {
9355 if (pid != kernel_policy->cond_pid) {
9356 // No match, does not match required pid
9357 return FALSE;
9358 }
9359 if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
9360 return FALSE;
9361 }
9362 }
9363 }
9364
9365 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9366 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9367 "NECP_KERNEL_CONDITION_UID",
9368 kernel_policy->cond_uid, uid);
9369 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9370 if (uid == kernel_policy->cond_uid) {
9371 // No match, matches forbidden uid
9372 return FALSE;
9373 }
9374 } else {
9375 if (uid != kernel_policy->cond_uid) {
9376 // No match, does not match required uid
9377 return FALSE;
9378 }
9379 }
9380 }
9381
9382 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9383 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9384 "NECP_KERNEL_CONDITION_REAL_UID",
9385 kernel_policy->cond_real_uid, real_uid);
9386 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9387 if (real_uid == kernel_policy->cond_real_uid) {
9388 // No match, matches forbidden uid
9389 return FALSE;
9390 }
9391 } else {
9392 if (real_uid != kernel_policy->cond_real_uid) {
9393 // No match, does not match required uid
9394 return FALSE;
9395 }
9396 }
9397 }
9398
9399 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9400 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9401 kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9402 traffic_class, 0, 0);
9403 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9404 if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9405 traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9406 // No match, matches forbidden traffic class
9407 return FALSE;
9408 }
9409 } else {
9410 if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9411 traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9412 // No match, does not match required traffic class
9413 return FALSE;
9414 }
9415 }
9416 }
9417
9418 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9419 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9420 "NECP_KERNEL_CONDITION_PROTOCOL",
9421 kernel_policy->cond_protocol, protocol);
9422 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9423 if (protocol == kernel_policy->cond_protocol) {
9424 // No match, matches forbidden protocol
9425 return FALSE;
9426 }
9427 } else {
9428 if (protocol != kernel_policy->cond_protocol) {
9429 // No match, does not match required protocol
9430 return FALSE;
9431 }
9432 }
9433 }
9434
9435 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9436 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9437 kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9438 "n/a", "n/a", "n/a");
9439 bool matches_agent_type = FALSE;
9440 for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9441 struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9442 if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9443 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) &&
9444 (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9445 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)) {
9446 // Found a required agent that matches
9447 matches_agent_type = TRUE;
9448 break;
9449 }
9450 }
9451 if (!matches_agent_type) {
9452 return FALSE;
9453 }
9454 }
9455
9456 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9457 bool is_local = FALSE;
9458 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9459
9460 if (rt != NULL) {
9461 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9462 } else {
9463 is_local = necp_is_route_local(remote, include_local_addresses);
9464 }
9465 if (info != NULL) {
9466 info->is_local = is_local;
9467 }
9468
9469 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);
9470 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9471 if (is_local) {
9472 // Match local-networks, fail
9473 return FALSE;
9474 }
9475 } else {
9476 if (!is_local) {
9477 // Either no route to validate or no match for local networks
9478 return FALSE;
9479 }
9480 }
9481 }
9482
9483 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9484 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9485 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9486 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9487 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9488 if (inRange) {
9489 return FALSE;
9490 }
9491 } else {
9492 if (!inRange) {
9493 return FALSE;
9494 }
9495 }
9496 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9497 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9498 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);
9499 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9500 if (inSubnet) {
9501 return FALSE;
9502 }
9503 } else {
9504 if (!inSubnet) {
9505 return FALSE;
9506 }
9507 }
9508 }
9509 }
9510
9511 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9512 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9513 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9514 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9515 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9516 if (inRange) {
9517 return FALSE;
9518 }
9519 } else {
9520 if (!inRange) {
9521 return FALSE;
9522 }
9523 }
9524 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9525 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9526 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);
9527 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9528 if (inSubnet) {
9529 return FALSE;
9530 }
9531 } else {
9532 if (!inSubnet) {
9533 return FALSE;
9534 }
9535 }
9536 }
9537 }
9538
9539 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9540 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9541 "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9542 kernel_policy->cond_client_flags, client_flags);
9543 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9544 if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9545 // Flags do match, and condition is negative, fail.
9546 return FALSE;
9547 }
9548 } else {
9549 if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9550 // Flags do not match, fail.
9551 return FALSE;
9552 }
9553 }
9554 }
9555
9556 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9557 bool isEmpty = necp_addr_is_empty(SA(local));
9558 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9559 "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9560 0, isEmpty);
9561 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9562 if (isEmpty) {
9563 return FALSE;
9564 }
9565 } else {
9566 if (!isEmpty) {
9567 return FALSE;
9568 }
9569 }
9570 }
9571
9572 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9573 bool isEmpty = necp_addr_is_empty(SA(remote));
9574 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9575 "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9576 0, isEmpty);
9577 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9578 if (isEmpty) {
9579 return FALSE;
9580 }
9581 } else {
9582 if (!isEmpty) {
9583 return FALSE;
9584 }
9585 }
9586 }
9587
9588 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9589 u_int16_t remote_port = 0;
9590 if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9591 remote_port = SIN(remote)->sin_port;
9592 }
9593 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9594 "NECP_KERNEL_CONDITION_SCHEME_PORT",
9595 scheme_port, remote_port);
9596 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9597 if (kernel_policy->cond_scheme_port == scheme_port ||
9598 kernel_policy->cond_scheme_port == remote_port) {
9599 return FALSE;
9600 }
9601 } else {
9602 if (kernel_policy->cond_scheme_port != scheme_port &&
9603 kernel_policy->cond_scheme_port != remote_port) {
9604 return FALSE;
9605 }
9606 }
9607 }
9608
9609 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9610 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9611 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9612 kernel_policy->cond_packet_filter_tags,
9613 pf_tag);
9614 bool tags_matched = false;
9615 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9616 if (pf_tag == PF_TAG_ID_STACK_DROP) {
9617 tags_matched = true;
9618 }
9619 }
9620
9621 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9622 if (tags_matched) {
9623 return FALSE;
9624 }
9625 } else {
9626 if (!tags_matched) {
9627 return FALSE;
9628 }
9629 }
9630 }
9631
9632 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9633 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9634 "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9635 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9636 if (is_loopback) {
9637 return FALSE;
9638 }
9639 } else {
9640 if (!is_loopback) {
9641 return FALSE;
9642 }
9643 }
9644 }
9645
9646 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9647 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9648 "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9649 if (is_delegated) {
9650 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9651 if (real_is_platform_binary) {
9652 return FALSE;
9653 }
9654 } else {
9655 if (!real_is_platform_binary) {
9656 return FALSE;
9657 }
9658 }
9659 } else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9660 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9661 // If the connection is not delegated, and the policy did not specify a particular effective process UUID
9662 // or PID, check the process directly
9663 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9664 if (is_platform_binary) {
9665 return FALSE;
9666 }
9667 } else {
9668 if (!is_platform_binary) {
9669 return FALSE;
9670 }
9671 }
9672 }
9673 }
9674
9675 return TRUE;
9676 }
9677
9678 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9679 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9680 {
9681 return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9682 }
9683
9684 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)9685 necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, soflow_direction_t override_direction, u_int32_t drop_order, proc_t *socket_proc, struct necp_socket_info *info, bool is_loopback, int input_ifindex)
9686 {
9687 struct socket *so = NULL;
9688 proc_t sock_proc = NULL;
9689 proc_t curr_proc = current_proc();
9690
9691 memset(info, 0, sizeof(struct necp_socket_info));
9692
9693 so = inp->inp_socket;
9694
9695 info->drop_order = drop_order;
9696 info->is_loopback = is_loopback;
9697 info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9698
9699 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9700 necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9701 info->uid = kauth_cred_getuid(so->so_cred);
9702 info->real_uid = info->uid;
9703 }
9704
9705 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9706 info->traffic_class = so->so_traffic_class;
9707 }
9708
9709 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9710 info->has_client = !uuid_is_null(inp->necp_client_uuid);
9711 }
9712
9713 if (inp->inp_ip_p) {
9714 info->protocol = inp->inp_ip_p;
9715 } else {
9716 info->protocol = SOCK_PROTO(so);
9717 }
9718
9719 if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9720 u_int32_t responsible_application_id = 0;
9721
9722 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9723 if (existing_mapping) {
9724 info->application_id = existing_mapping->id;
9725 }
9726
9727 #if defined(XNU_TARGET_OS_OSX)
9728 if (so->so_rpid > 0) {
9729 existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9730 if (existing_mapping != NULL) {
9731 responsible_application_id = existing_mapping->id;
9732 }
9733 }
9734 #endif
9735
9736 if (responsible_application_id > 0) {
9737 info->real_application_id = info->application_id;
9738 info->application_id = responsible_application_id;
9739 info->used_responsible_pid = true;
9740 } else if (!(so->so_flags & SOF_DELEGATED)) {
9741 info->real_application_id = info->application_id;
9742 } else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9743 struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9744 if (real_existing_mapping) {
9745 info->real_application_id = real_existing_mapping->id;
9746 }
9747 }
9748 }
9749
9750 pid_t socket_pid =
9751 #if defined(XNU_TARGET_OS_OSX)
9752 info->used_responsible_pid ? so->so_rpid :
9753 #endif
9754 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9755 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9756 sock_proc = proc_find(socket_pid);
9757 if (socket_proc) {
9758 *socket_proc = sock_proc;
9759 }
9760 }
9761
9762 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9763 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9764 info->is_entitled = necp_task_has_match_entitlement(task);
9765 if (!info->is_entitled) {
9766 // Task does not have entitlement, check the parent task
9767 necp_get_parent_is_entitled(task, info);
9768 }
9769 }
9770
9771 info->pid = socket_pid;
9772 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9773 info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9774 }
9775
9776 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9777 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9778 if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9779 info->is_platform_binary = true;
9780 } else if (so->so_rpid != 0) {
9781 proc_t responsible_proc = proc_find(so->so_rpid);
9782 if (responsible_proc != NULL) {
9783 if (necp_is_platform_binary(responsible_proc)) {
9784 info->is_platform_binary = true;
9785 info->used_responsible_pid = true;
9786 }
9787 proc_rele(responsible_proc);
9788 }
9789 }
9790 }
9791
9792 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9793 proc_t real_proc = curr_proc;
9794 bool release_real_proc = false;
9795 if (so->last_pid != proc_pid(real_proc)) {
9796 if (so->last_pid == socket_pid && sock_proc != NULL) {
9797 real_proc = sock_proc;
9798 } else {
9799 proc_t last_proc = proc_find(so->last_pid);
9800 if (last_proc != NULL) {
9801 real_proc = last_proc;
9802 release_real_proc = true;
9803 }
9804 }
9805 }
9806 if (real_proc != NULL) {
9807 if (real_proc == kernproc) {
9808 info->real_is_platform_binary = true;
9809 } else {
9810 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9811 }
9812 if (release_real_proc) {
9813 proc_rele(real_proc);
9814 }
9815 }
9816 }
9817
9818 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9819 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9820 if (existing_mapping) {
9821 info->account_id = existing_mapping->id;
9822 }
9823 }
9824
9825 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9826 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9827 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9828 info->domain = inp->inp_necp_attributes.inp_domain;
9829 }
9830
9831 if (override_bound_interface) {
9832 info->bound_interface_index = override_bound_interface;
9833 } else {
9834 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9835 info->bound_interface_index = inp->inp_boundifp->if_index;
9836 }
9837 }
9838
9839 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9840 info->bound_interface_index != IFSCOPE_NONE) {
9841 ifnet_head_lock_shared();
9842 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9843 if (interface != NULL) {
9844 info->bound_interface_flags = interface->if_flags;
9845 info->bound_interface_eflags = interface->if_eflags;
9846 info->bound_interface_xflags = interface->if_xflags;
9847 }
9848 ifnet_head_done();
9849 }
9850
9851 bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9852 uuid_is_null(inp->necp_client_uuid) &&
9853 necp_socket_has_resolver_signature(inp));
9854 if ((necp_data_tracing_level && necp_data_tracing_port) ||
9855 necp_restrict_multicast ||
9856 needs_address_for_signature ||
9857 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) ||
9858 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS)) {
9859 if (override_local_addr != NULL) {
9860 if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9861 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9862 if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9863 struct sockaddr_in sin;
9864 in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9865 memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9866 memcpy(&info->local_addr, &sin, sin.sin_len);
9867 }
9868 } else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9869 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9870 }
9871 } else {
9872 if (inp->inp_vflag & INP_IPV6) {
9873 SIN6(&info->local_addr)->sin6_family = AF_INET6;
9874 SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9875 SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9876 memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9877 } else if (inp->inp_vflag & INP_IPV4) {
9878 SIN(&info->local_addr)->sin_family = AF_INET;
9879 SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9880 SIN(&info->local_addr)->sin_port = inp->inp_lport;
9881 memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9882 }
9883 }
9884
9885 if (override_remote_addr != NULL) {
9886 if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9887 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9888 if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9889 struct sockaddr_in sin;
9890 in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9891 memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9892 memcpy(&info->remote_addr, &sin, sin.sin_len);
9893 }
9894 } else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9895 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9896 }
9897 } else {
9898 if (inp->inp_vflag & INP_IPV6) {
9899 SIN6(&info->remote_addr)->sin6_family = AF_INET6;
9900 SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9901 SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
9902 memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
9903 } else if (inp->inp_vflag & INP_IPV4) {
9904 SIN(&info->remote_addr)->sin_family = AF_INET;
9905 SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9906 SIN(&info->remote_addr)->sin_port = inp->inp_fport;
9907 memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
9908 }
9909 }
9910 // Clear the embedded scope id from v6 addresses
9911 if (info->local_addr.sa.sa_family == AF_INET6) {
9912 struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
9913 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9914 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9915 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9916 sin6->sin6_addr.s6_addr16[1] = 0;
9917 }
9918 }
9919 }
9920 if (info->remote_addr.sa.sa_family == AF_INET6) {
9921 struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
9922 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9923 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9924 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9925 sin6->sin6_addr.s6_addr16[1] = 0;
9926 }
9927 }
9928 }
9929 }
9930
9931 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9932 // For checking sockets, only validate that there is an NECP client present. It will have
9933 // already checked for the signature.
9934 if (!uuid_is_null(inp->necp_client_uuid)) {
9935 info->has_system_signed_result = true;
9936 } else {
9937 info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
9938 }
9939 }
9940
9941 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9942 info->client_flags = 0;
9943 if (INP_NO_CONSTRAINED(inp)) {
9944 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
9945 }
9946 if (INP_NO_EXPENSIVE(inp)) {
9947 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
9948 }
9949 if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
9950 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
9951 }
9952 if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
9953 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
9954 }
9955 if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
9956 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
9957 }
9958 if (NEED_DGRAM_FLOW_TRACKING(so)) {
9959 if (!necp_socket_is_connected(inp)) {
9960 // If the socket has a flow entry for this 4-tuple then check if the flow is outgoing
9961 // and set the inbound flag accordingly. Otherwise use the direction to set the inbound flag.
9962 struct soflow_hash_entry *flow = soflow_get_flow(so, &info->local_addr.sa, &info->remote_addr.sa, NULL, 0, override_direction, input_ifindex);
9963 if (flow != NULL) {
9964 if (!flow->soflow_outgoing) {
9965 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9966 }
9967 soflow_free_flow(flow);
9968 } else if (override_direction == SOFLOW_DIRECTION_INBOUND) {
9969 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9970 }
9971 }
9972 } else {
9973 // If the socket is explicitly marked as inbound then set the inbound flag.
9974 if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
9975 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9976 }
9977 }
9978 if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
9979 inp->inp_flags2 & INP2_EXTERNAL_PORT) {
9980 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
9981 }
9982 if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
9983 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
9984 }
9985 if (inp->inp_socket->so_options & SO_REUSEPORT) {
9986 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
9987 }
9988 }
9989 }
9990
9991 #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)
9992
9993 static inline struct necp_kernel_socket_policy *
necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,struct necp_socket_info * info,necp_kernel_policy_filter * return_filter,u_int32_t * __counted_by (route_rule_id_array_count)return_route_rule_id_array,size_t * return_route_rule_id_array_count,size_t route_rule_id_array_count,necp_kernel_policy_result * return_service_action,necp_kernel_policy_service * return_service,u_int32_t * __counted_by (netagent_array_count)return_netagent_array,size_t netagent_array_count,u_int32_t * __counted_by (netagent_use_flags_array_count)return_netagent_use_flags_array,size_t netagent_use_flags_array_count,struct necp_client_parameter_netagent_type * __counted_by (num_required_agent_types)required_agent_types,u_int32_t num_required_agent_types,proc_t proc,u_int16_t pf_tag,necp_kernel_policy_id * skip_policy_id,struct rtentry * rt,necp_kernel_policy_result * return_drop_dest_policy_result,necp_drop_all_bypass_check_result_t * return_drop_all_bypass,u_int32_t * return_flow_divert_aggregate_unit,struct socket * so,int debug)9994 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
9995 struct necp_socket_info *info,
9996 necp_kernel_policy_filter *return_filter,
9997 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
9998 size_t *return_route_rule_id_array_count,
9999 size_t route_rule_id_array_count,
10000 necp_kernel_policy_result *return_service_action,
10001 necp_kernel_policy_service *return_service,
10002 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
10003 size_t netagent_array_count,
10004 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
10005 size_t netagent_use_flags_array_count,
10006 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
10007 u_int32_t num_required_agent_types,
10008 proc_t proc,
10009 u_int16_t pf_tag,
10010 necp_kernel_policy_id *skip_policy_id,
10011 struct rtentry *rt,
10012 necp_kernel_policy_result *return_drop_dest_policy_result,
10013 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
10014 u_int32_t *return_flow_divert_aggregate_unit,
10015 struct socket *so,
10016 int debug)
10017 {
10018 struct necp_kernel_socket_policy *matched_policy = NULL;
10019 u_int32_t skip_order = 0;
10020 u_int32_t skip_session_order = 0;
10021 bool skipped_ip_result = false;
10022 size_t route_rule_id_count = 0;
10023 int i;
10024 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10025 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
10026 memset(&netagent_ids, 0, sizeof(netagent_ids));
10027 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
10028 size_t netagent_cursor = 0;
10029 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10030 size_t netagent_array_count_adjusted = netagent_array_count;
10031 if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
10032 netagent_array_count_adjusted = netagent_use_flags_array_count;
10033 }
10034
10035 if (return_drop_all_bypass != NULL) {
10036 *return_drop_all_bypass = drop_all_bypass;
10037 }
10038
10039 if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
10040 netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
10041 }
10042
10043 // Pre-process domain for quick matching
10044 struct substring domain_substring = {};
10045 u_int8_t domain_dot_count = 0;
10046 if (info->domain != NULL) {
10047 domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
10048 domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
10049 }
10050
10051 if (return_filter != NULL) {
10052 *return_filter = 0;
10053 }
10054
10055 if (return_route_rule_id_array_count != NULL) {
10056 *return_route_rule_id_array_count = 0;
10057 }
10058
10059 if (return_service_action != NULL) {
10060 *return_service_action = 0;
10061 }
10062
10063 if (return_service != NULL) {
10064 return_service->identifier = 0;
10065 return_service->data = 0;
10066 }
10067
10068 // Do not subject layer-2 filter to NECP policies, return a PASS policy
10069 if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
10070 return &pass_policy;
10071 }
10072
10073 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10074
10075 if (policy_search_array != NULL) {
10076 for (i = 0; policy_search_array[i] != NULL; i++) {
10077 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
10078
10079 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10080 // We've hit a drop all rule
10081 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10082 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
10083 if (return_drop_all_bypass != NULL) {
10084 *return_drop_all_bypass = drop_all_bypass;
10085 }
10086 }
10087 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10088 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
10089 break;
10090 }
10091 }
10092 if (necp_drop_dest_policy.entry_count != 0 &&
10093 necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
10094 // We've hit a drop by destination address rule
10095 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10096 break;
10097 }
10098 if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
10099 // We've hit a drop order for this socket
10100 break;
10101 }
10102 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10103 // Done skipping
10104 skip_order = 0;
10105 skip_session_order = 0;
10106 // If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
10107 if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
10108 *skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10109 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
10110 }
10111 }
10112 if (skip_order) {
10113 if (policy_search_array[i]->order < skip_order) {
10114 // Skip this policy
10115 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10116 // didn't, clear out the return value for skip ID when we are done with each session.'
10117 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10118 skipped_ip_result = true;
10119 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10120 }
10121 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
10122 continue;
10123 } else {
10124 // Done skipping
10125 skip_order = 0;
10126 skip_session_order = 0;
10127 }
10128 } else if (skip_session_order) {
10129 // Skip this policy
10130 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10131 // didn't, clear out the return value for skip ID when we are done with each session.'
10132 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10133 skipped_ip_result = true;
10134 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10135 }
10136 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
10137 continue;
10138 }
10139
10140 if (necp_socket_check_policy(policy_search_array[i],
10141 info->application_id,
10142 info->real_application_id,
10143 info->is_entitled,
10144 info->account_id,
10145 domain_substring,
10146 domain_dot_count,
10147 info->url,
10148 info->pid,
10149 info->pid_version,
10150 info->uid,
10151 info->real_uid,
10152 info->bound_interface_index,
10153 info->traffic_class,
10154 info->protocol,
10155 &info->local_addr,
10156 &info->remote_addr,
10157 required_agent_types,
10158 num_required_agent_types,
10159 info->has_client,
10160 info->client_flags,
10161 info->is_platform_binary,
10162 info->has_system_signed_result,
10163 proc,
10164 pf_tag,
10165 info->scheme_port,
10166 rt,
10167 info->is_loopback,
10168 debug,
10169 info->real_is_platform_binary,
10170 info->bound_interface_flags,
10171 info->bound_interface_eflags,
10172 info->bound_interface_xflags,
10173 info,
10174 info->is_delegated,
10175 so)) {
10176 if (!debug && necp_data_tracing_session_order) {
10177 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10178 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10179 NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
10180 }
10181 }
10182
10183 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
10184 if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
10185 necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
10186 if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
10187 *return_filter = control_unit;
10188 } else {
10189 // Preserve pre-existing connections only if all filters preserve.
10190 bool preserve_bit_off = false;
10191 if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
10192 (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
10193 preserve_bit_off = true;
10194 }
10195 *return_filter |= control_unit;
10196 if (preserve_bit_off == true) {
10197 *return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
10198 }
10199 }
10200 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10201 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, policy_search_array[i]->result_parameter.filter_control_unit);
10202 }
10203 }
10204 continue;
10205 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10206 if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
10207 return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10208 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10209 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) 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);
10210 }
10211 }
10212 continue;
10213 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
10214 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10215 if (netagent_cursor < netagent_array_count_adjusted) {
10216 bool agent_already_present = false;
10217 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10218 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10219 // Already present. Mark the "SCOPED" flag if flags are necessary.
10220 agent_already_present = true;
10221 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
10222 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10223 netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
10224 }
10225 }
10226 }
10227
10228 if (!agent_already_present) {
10229 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10230 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10231 netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
10232 }
10233 netagent_cursor++;
10234 }
10235 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10236 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
10237 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10238 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
10239 policy_search_array[i]->result_parameter.netagent_id);
10240 }
10241 }
10242 continue;
10243 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
10244 bool agent_already_present = false;
10245 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10246 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10247 // Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10248 agent_already_present = true;
10249 netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10250 }
10251 }
10252 if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10253 // If not present, and flags are supported, add an entry with the "REMOVE" flag
10254 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10255 netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10256 netagent_cursor++;
10257 }
10258 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10259 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
10260 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10261 policy_search_array[i]->result_parameter.netagent_id);
10262 }
10263 continue;
10264 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
10265 u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
10266 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
10267 /* For transparent proxies, accumulate the control unit and continue to the next policy */
10268 if (return_flow_divert_aggregate_unit != NULL) {
10269 *return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
10270 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10271 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);
10272 }
10273 }
10274 continue;
10275 }
10276 }
10277
10278 // Matched policy is a skip. Do skip and continue.
10279 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10280 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
10281 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10282 skip_session_order = policy_search_array[i]->session_order + 1;
10283 if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
10284 *skip_policy_id = policy_search_array[i]->id;
10285 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10286 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);
10287 }
10288 }
10289 continue;
10290 }
10291
10292 // Matched an allow unentitled, which clears any drop order
10293 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
10294 info->drop_order = 0;
10295 continue;
10296 }
10297
10298 // Passed all tests, found a match
10299 matched_policy = policy_search_array[i];
10300 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
10301 break;
10302 }
10303 }
10304 }
10305
10306 if (return_netagent_array != NULL) {
10307 if (return_netagent_use_flags_array != NULL) {
10308 memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
10309 memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
10310 } else {
10311 for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
10312 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
10313 return_netagent_array[netagent_i] = netagent_ids[netagent_i];
10314 } else {
10315 return_netagent_array[netagent_i] = 0;
10316 }
10317 }
10318 }
10319 }
10320
10321 if (return_route_rule_id_array_count != NULL) {
10322 *return_route_rule_id_array_count = route_rule_id_count;
10323 }
10324 return matched_policy;
10325 }
10326
10327 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)10328 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
10329 {
10330 bool found_match = FALSE;
10331 ifaddr_t ifa;
10332 union necp_sockaddr_union address_storage;
10333 int family = AF_INET;
10334
10335 ifnet_head_lock_shared();
10336 ifnet_t interface = ifindex2ifnet[interface_index];
10337 ifnet_head_done();
10338
10339 if (inp == NULL || interface == NULL) {
10340 return FALSE;
10341 }
10342
10343 if (inp->inp_vflag & INP_IPV4) {
10344 family = AF_INET;
10345 } else if (inp->inp_vflag & INP_IPV6) {
10346 family = AF_INET6;
10347 } else {
10348 return FALSE;
10349 }
10350
10351 // Match socket address against interface addresses
10352 ifnet_lock_shared(interface);
10353 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
10354 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
10355 if (address_storage.sa.sa_family != family) {
10356 continue;
10357 }
10358
10359 if (family == AF_INET) {
10360 if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
10361 found_match = TRUE;
10362 break;
10363 }
10364 } else if (family == AF_INET6) {
10365 if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
10366 found_match = TRUE;
10367 break;
10368 }
10369 }
10370 }
10371 }
10372 ifnet_lock_done(interface);
10373
10374 return found_match;
10375 }
10376
10377 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10378 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10379 {
10380 if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10381 proc_t curr_proc = current_proc();
10382 proc_t sock_proc = NULL;
10383 struct socket *so = inp ? inp->inp_socket : NULL;
10384 pid_t socket_pid = (so == NULL) ? 0 :
10385 #if defined(XNU_TARGET_OS_OSX)
10386 so->so_rpid ? so->so_rpid :
10387 #endif
10388 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10389 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10390 sock_proc = proc_find(socket_pid);
10391 }
10392 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10393 if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10394 if (sock_proc) {
10395 proc_rele(sock_proc);
10396 }
10397 return NECP_BYPASS_TYPE_DROP;
10398 }
10399 if (sock_proc) {
10400 proc_rele(sock_proc);
10401 }
10402
10403 if (necp_pass_loopback > 0) {
10404 return NECP_BYPASS_TYPE_LOOPBACK;
10405 }
10406 } else if (necp_is_intcoproc(inp, NULL)) {
10407 return NECP_BYPASS_TYPE_INTCOPROC;
10408 }
10409
10410 return NECP_BYPASS_TYPE_NONE;
10411 }
10412
10413 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10414 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10415 {
10416 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10417 ifnet_t tunnel_interface = NULL;
10418
10419 ifnet_head_lock_shared();
10420 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10421 ifnet_head_done();
10422
10423 if (tunnel_interface != NULL) {
10424 tcp_set_tso(intotcpcb(inp), tunnel_interface);
10425 }
10426 }
10427
10428 static inline void
necp_unscope(struct inpcb * inp)10429 necp_unscope(struct inpcb *inp)
10430 {
10431 // If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10432 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10433 inp->inp_flags &= ~INP_BOUND_IF;
10434 inp->inp_boundifp = NULL;
10435 }
10436 }
10437
10438 static inline void
necp_clear_tunnel(struct inpcb * inp)10439 necp_clear_tunnel(struct inpcb *inp)
10440 {
10441 if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10442 inp->inp_flags &= ~INP_BOUND_IF;
10443 inp->inp_boundifp = NULL;
10444 }
10445 }
10446
10447 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10448 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10449 {
10450 // Verify netagents
10451 for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10452 struct necp_uuid_id_mapping *mapping = NULL;
10453 u_int32_t netagent_id = netagent_ids[netagent_cursor];
10454 if (netagent_id == 0) {
10455 continue;
10456 }
10457 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
10458 if (mapping != NULL) {
10459 u_int32_t agent_flags = 0;
10460 agent_flags = netagent_get_flags(mapping->uuid);
10461 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10462 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10463 continue;
10464 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10465 if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10466 int trigger_error = 0;
10467 trigger_error = netagent_kernel_trigger(mapping->uuid);
10468 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10469 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);
10470 }
10471 }
10472 return false;
10473 }
10474 }
10475 }
10476 }
10477 return true;
10478 }
10479
10480 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)10481 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10482 {
10483 struct socket *so = NULL;
10484 necp_kernel_policy_filter filter_control_unit = 0;
10485 struct necp_kernel_socket_policy *matched_policy = NULL;
10486 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10487 necp_kernel_policy_result service_action = 0;
10488 necp_kernel_policy_service service = { 0, 0 };
10489 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10490 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10491 proc_t __single socket_proc = NULL;
10492 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10493
10494 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10495 memset(&netagent_ids, 0, sizeof(netagent_ids));
10496
10497 struct necp_socket_info info = {};
10498
10499 u_int32_t flow_divert_aggregate_unit = 0;
10500
10501 if (inp == NULL) {
10502 return NECP_KERNEL_POLICY_ID_NONE;
10503 }
10504
10505 // Ignore invalid addresses
10506 if (override_local_addr != NULL &&
10507 !necp_address_is_valid(override_local_addr)) {
10508 override_local_addr = NULL;
10509 }
10510 if (override_remote_addr != NULL &&
10511 !necp_address_is_valid(override_remote_addr)) {
10512 override_remote_addr = NULL;
10513 }
10514
10515 so = inp->inp_socket;
10516
10517 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10518
10519 // Don't lock. Possible race condition, but we don't want the performance hit.
10520 if (necp_drop_management_order == 0 &&
10521 (necp_kernel_socket_policies_count == 0 ||
10522 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10523 if (necp_drop_all_order > 0 || drop_order > 0) {
10524 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10525 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10526 inp->inp_policyresult.policy_gencount = 0;
10527 inp->inp_policyresult.app_id = 0;
10528 inp->inp_policyresult.flowhash = 0;
10529 inp->inp_policyresult.results.filter_control_unit = 0;
10530 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10531 inp->inp_policyresult.results.route_rule_id = 0;
10532 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10533 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10534 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10535 } else {
10536 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10537 }
10538 }
10539 return NECP_KERNEL_POLICY_ID_NONE;
10540 }
10541
10542 // Check for loopback exception
10543 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10544 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10545 // Mark socket as a drop
10546 necp_unscope(inp);
10547 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10548 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10549 inp->inp_policyresult.policy_gencount = 0;
10550 inp->inp_policyresult.app_id = 0;
10551 inp->inp_policyresult.flowhash = 0;
10552 inp->inp_policyresult.results.filter_control_unit = 0;
10553 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10554 inp->inp_policyresult.results.route_rule_id = 0;
10555 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10556 return NECP_KERNEL_POLICY_ID_NONE;
10557 }
10558
10559 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10560 // Mark socket as a pass
10561 necp_unscope(inp);
10562 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10563 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10564 inp->inp_policyresult.policy_gencount = 0;
10565 inp->inp_policyresult.app_id = 0;
10566 inp->inp_policyresult.flowhash = 0;
10567 inp->inp_policyresult.results.filter_control_unit = 0;
10568 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10569 inp->inp_policyresult.results.route_rule_id = 0;
10570 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10571 return NECP_KERNEL_POLICY_ID_NONE;
10572 }
10573
10574 // Lock
10575 lck_rw_lock_shared(&necp_kernel_policy_lock);
10576 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);
10577
10578 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10579 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10580
10581 // Check info
10582 u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10583 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10584 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10585 inp->inp_policyresult.flowhash == flowhash) {
10586 // If already matched this socket on this generation of table, skip
10587
10588 // Unlock
10589 lck_rw_done(&necp_kernel_policy_lock);
10590
10591 if (socket_proc) {
10592 proc_rele(socket_proc);
10593 }
10594
10595 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10596 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10597 inp->inp_socket, info.bound_interface_index, info.protocol,
10598 inp->inp_policyresult.policy_id,
10599 inp->inp_policyresult.results.result,
10600 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10601 }
10602 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10603 return inp->inp_policyresult.policy_id;
10604 }
10605
10606 inp->inp_policyresult.app_id = info.application_id;
10607
10608 // Match socket to policy
10609 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10610 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10611 size_t route_rule_id_array_count = 0;
10612
10613 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10614 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)],
10615 &info,
10616 &filter_control_unit,
10617 route_rule_id_array,
10618 &route_rule_id_array_count,
10619 MAX_AGGREGATE_ROUTE_RULES,
10620 &service_action,
10621 &service,
10622 netagent_ids,
10623 NECP_MAX_NETAGENTS,
10624 NULL,
10625 0,
10626 NULL,
10627 0,
10628 effective_proc,
10629 0,
10630 &skip_policy_id,
10631 inp->inp_route.ro_rt,
10632 &drop_dest_policy_result,
10633 &drop_all_bypass,
10634 &flow_divert_aggregate_unit,
10635 so,
10636 debug);
10637
10638 // Check for loopback exception again after the policy match
10639 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10640 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10641 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10642 // Mark socket as a pass
10643 necp_unscope(inp);
10644 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10645 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10646 inp->inp_policyresult.policy_gencount = 0;
10647 inp->inp_policyresult.app_id = 0;
10648 inp->inp_policyresult.flowhash = 0;
10649 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10650 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10651 inp->inp_policyresult.results.route_rule_id = 0;
10652 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10653
10654 // Unlock
10655 lck_rw_done(&necp_kernel_policy_lock);
10656
10657 if (socket_proc) {
10658 proc_rele(socket_proc);
10659 }
10660
10661 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10662 return NECP_KERNEL_POLICY_ID_NONE;
10663 }
10664
10665 // Verify netagents
10666 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10667 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10668 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);
10669 }
10670
10671 // Mark socket as a drop if required agent is not active
10672 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10673 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10674 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10675 inp->inp_policyresult.flowhash = flowhash;
10676 inp->inp_policyresult.results.filter_control_unit = 0;
10677 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10678 inp->inp_policyresult.results.route_rule_id = 0;
10679 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10680
10681 // Unlock
10682 lck_rw_done(&necp_kernel_policy_lock);
10683
10684 if (socket_proc) {
10685 proc_rele(socket_proc);
10686 }
10687
10688 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);
10689 return NECP_KERNEL_POLICY_ID_NONE;
10690 }
10691
10692 u_int32_t route_rule_id = 0;
10693 if (route_rule_id_array_count == 1) {
10694 route_rule_id = route_rule_id_array[0];
10695 } else if (route_rule_id_array_count > 1) {
10696 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10697 }
10698
10699 bool reset_tcp_tunnel_interface = false;
10700 bool send_local_network_denied_event = false;
10701 if (matched_policy) {
10702 // For PASS policy result, clear previous rescope / tunnel inteface
10703 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10704 (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10705 necp_unscope(inp);
10706 necp_clear_tunnel(inp);
10707 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10708 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10709 }
10710 }
10711 matched_policy_id = matched_policy->id;
10712 inp->inp_policyresult.policy_id = matched_policy->id;
10713 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10714 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10715 inp->inp_policyresult.flowhash = flowhash;
10716 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10717 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10718 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10719 inp->inp_policyresult.results.result = matched_policy->result;
10720 memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10721
10722 if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10723 inp->inp_policyresult.app_id = info.real_application_id;
10724 }
10725
10726 if (necp_socket_is_connected(inp) &&
10727 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10728 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10729 NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10730 sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10731 } else if (necp_socket_is_connected(inp) &&
10732 matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10733 info.protocol == IPPROTO_TCP) {
10734 // Reset TCP socket interface based parameters if tunnel policy changes
10735 reset_tcp_tunnel_interface = true;
10736 }
10737
10738 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10739 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);
10740 }
10741
10742 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10743 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10744 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10745 // Trigger the event that we dropped due to a local network policy
10746 send_local_network_denied_event = true;
10747 }
10748 } else {
10749 bool drop_all = false;
10750 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10751 // Mark socket as a drop if set
10752 drop_all = true;
10753 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10754 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10755 }
10756 }
10757
10758 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10759 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);
10760 if (flow_divert_control_unit != 0) {
10761 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10762 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10763 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10764 inp->inp_policyresult.flowhash = flowhash;
10765 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10766 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10767 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10768 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10769 inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10770 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);
10771 } else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10772 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10773 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10774 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10775 inp->inp_policyresult.flowhash = flowhash;
10776 inp->inp_policyresult.results.filter_control_unit = 0;
10777 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10778 inp->inp_policyresult.results.route_rule_id = 0;
10779 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10780 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);
10781 } else {
10782 // Mark non-matching socket so we don't re-check it
10783 necp_unscope(inp);
10784 if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10785 necp_clear_tunnel(inp);
10786 }
10787 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10788 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);
10789 }
10790 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10791 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10792 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10793 inp->inp_policyresult.flowhash = flowhash;
10794 inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10795 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10796 inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10797 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10798 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10799 }
10800 }
10801
10802 if (necp_check_missing_client_drop(effective_proc, &info) ||
10803 necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10804 // Mark as drop
10805 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10806 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10807 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10808 inp->inp_policyresult.flowhash = flowhash;
10809 inp->inp_policyresult.results.filter_control_unit = 0;
10810 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10811 inp->inp_policyresult.results.route_rule_id = 0;
10812 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10813 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10814 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10815 }
10816 }
10817
10818 // Unlock
10819 lck_rw_done(&necp_kernel_policy_lock);
10820
10821 if (reset_tcp_tunnel_interface) {
10822 // Update MSS when not holding the policy lock to avoid recursive locking
10823 tcp_mtudisc(inp, 0);
10824
10825 // Update TSO flag based on the tunnel interface
10826 necp_socket_ip_tunnel_tso(inp);
10827 }
10828
10829 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10830 inp->inp_policyresult.network_denied_notifies++;
10831 #if defined(XNU_TARGET_OS_OSX)
10832 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10833 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10834 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10835 NETPOLICY_NETWORKTYPE_LOCAL);
10836 #else
10837 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10838 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10839 NETPOLICY_NETWORKTYPE_LOCAL);
10840 #endif
10841 }
10842
10843 if (socket_proc) {
10844 proc_rele(socket_proc);
10845 }
10846
10847 return matched_policy_id;
10848 }
10849
10850 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)10851 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)
10852 {
10853 u_int32_t bound_interface_flags = 0;
10854 u_int32_t bound_interface_eflags = 0;
10855 u_int32_t bound_interface_xflags = 0;
10856
10857 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
10858 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10859 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
10860 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
10861 "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
10862 cond_bound_interface_index, bound_interface_index);
10863 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10864 if (bound_interface_index == cond_bound_interface_index) {
10865 // No match, matches forbidden interface
10866 return FALSE;
10867 }
10868 } else {
10869 if (bound_interface_index != cond_bound_interface_index) {
10870 // No match, does not match required interface
10871 return FALSE;
10872 }
10873 }
10874 }
10875 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10876 if (bound_interface_index != IFSCOPE_NONE) {
10877 ifnet_head_lock_shared();
10878 ifnet_t interface = ifindex2ifnet[bound_interface_index];
10879 if (interface != NULL) {
10880 bound_interface_flags = interface->if_flags;
10881 bound_interface_eflags = interface->if_eflags;
10882 bound_interface_xflags = interface->if_xflags;
10883 }
10884 ifnet_head_done();
10885 }
10886
10887 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10888 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
10889 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10890 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
10891 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10892 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
10893 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10894 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10895 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10896 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10897 // No match, matches some forbidden interface flags
10898 return FALSE;
10899 }
10900 } else {
10901 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10902 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10903 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10904 // No match, does not match some required interface xflags
10905 return FALSE;
10906 }
10907 }
10908 }
10909 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
10910 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
10911 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
10912 if (bound_interface_index != 0) {
10913 // No match, requires a non-bound packet
10914 return FALSE;
10915 }
10916 }
10917 }
10918
10919 if (kernel_policy->condition_mask == 0) {
10920 return TRUE;
10921 }
10922
10923 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10924 necp_kernel_policy_id matched_policy_id =
10925 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10926 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
10927 "NECP_KERNEL_CONDITION_POLICY_ID",
10928 kernel_policy->cond_policy_id, 0, 0,
10929 matched_policy_id, socket_policy_id, socket_skip_policy_id);
10930 if (matched_policy_id != kernel_policy->cond_policy_id) {
10931 // No match, does not match required id
10932 return FALSE;
10933 }
10934 }
10935
10936 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10937 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
10938 "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10939 kernel_policy->cond_last_interface_index, last_interface_index);
10940 if (last_interface_index != kernel_policy->cond_last_interface_index) {
10941 return FALSE;
10942 }
10943 }
10944
10945 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10946 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
10947 "NECP_KERNEL_CONDITION_PROTOCOL",
10948 kernel_policy->cond_protocol, protocol);
10949 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10950 if (protocol == kernel_policy->cond_protocol) {
10951 // No match, matches forbidden protocol
10952 return FALSE;
10953 }
10954 } else {
10955 if (protocol != kernel_policy->cond_protocol) {
10956 // No match, does not match required protocol
10957 return FALSE;
10958 }
10959 }
10960 }
10961
10962 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10963 bool is_local = FALSE;
10964 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
10965
10966 if (rt != NULL) {
10967 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
10968 } else {
10969 is_local = necp_is_route_local(remote, include_local_addresses);
10970 }
10971 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);
10972 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10973 if (is_local) {
10974 // Match local-networks, fail
10975 return FALSE;
10976 }
10977 } else {
10978 if (!is_local) {
10979 // Either no route to validate or no match for local networks
10980 return FALSE;
10981 }
10982 }
10983 }
10984
10985 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
10986 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10987 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
10988 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
10989 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10990 if (inRange) {
10991 return FALSE;
10992 }
10993 } else {
10994 if (!inRange) {
10995 return FALSE;
10996 }
10997 }
10998 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10999 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
11000 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
11001 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11002 if (inSubnet) {
11003 return FALSE;
11004 }
11005 } else {
11006 if (!inSubnet) {
11007 return FALSE;
11008 }
11009 }
11010 }
11011 }
11012
11013 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
11014 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11015 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
11016 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
11017 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11018 if (inRange) {
11019 return FALSE;
11020 }
11021 } else {
11022 if (!inRange) {
11023 return FALSE;
11024 }
11025 }
11026 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11027 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
11028 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
11029 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11030 if (inSubnet) {
11031 return FALSE;
11032 }
11033 } else {
11034 if (!inSubnet) {
11035 return FALSE;
11036 }
11037 }
11038 }
11039 }
11040
11041 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11042 u_int16_t remote_port = 0;
11043 if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
11044 remote_port = SIN(remote)->sin_port;
11045 }
11046 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
11047 "NECP_KERNEL_CONDITION_SCHEME_PORT",
11048 0, remote_port);
11049 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11050 if (kernel_policy->cond_scheme_port == remote_port) {
11051 return FALSE;
11052 }
11053 } else {
11054 if (kernel_policy->cond_scheme_port != remote_port) {
11055 return FALSE;
11056 }
11057 }
11058 }
11059
11060 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11061 bool tags_matched = false;
11062 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
11063 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
11064 kernel_policy->cond_packet_filter_tags, pf_tag);
11065 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
11066 if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
11067 tags_matched = true;
11068 }
11069
11070 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11071 if (tags_matched) {
11072 return FALSE;
11073 }
11074 } else {
11075 if (!tags_matched) {
11076 return FALSE;
11077 }
11078 }
11079 }
11080 }
11081
11082 return TRUE;
11083 }
11084
11085 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)11086 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)
11087 {
11088 u_int32_t skip_order = 0;
11089 u_int32_t skip_session_order = 0;
11090 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11091 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)];
11092 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11093 size_t route_rule_id_count = 0;
11094 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11095 if (return_drop_all_bypass != NULL) {
11096 *return_drop_all_bypass = drop_all_bypass;
11097 }
11098
11099 if (return_route_rule_id != NULL) {
11100 *return_route_rule_id = 0;
11101 }
11102
11103 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11104
11105 if (policy_search_array != NULL) {
11106 for (int i = 0; policy_search_array[i] != NULL; i++) {
11107 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
11108 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
11109 // We've hit a drop all rule
11110 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11111 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11112 if (return_drop_all_bypass != NULL) {
11113 *return_drop_all_bypass = drop_all_bypass;
11114 }
11115 }
11116 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11117 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
11118 break;
11119 }
11120 }
11121 if (necp_drop_dest_policy.entry_count > 0 &&
11122 necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
11123 // We've hit a drop by destination address rule
11124 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
11125 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
11126 break;
11127 }
11128 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
11129 // Done skipping
11130 skip_order = 0;
11131 skip_session_order = 0;
11132 }
11133 if (skip_order) {
11134 if (policy_search_array[i]->order < skip_order) {
11135 // Skip this policy
11136 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
11137 continue;
11138 } else {
11139 // Done skipping
11140 skip_order = 0;
11141 skip_session_order = 0;
11142 }
11143 } else if (skip_session_order) {
11144 // Skip this policy
11145 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
11146 continue;
11147 }
11148
11149 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)) {
11150 if (!debug && necp_data_tracing_session_order) {
11151 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
11152 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
11153 NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
11154 }
11155 }
11156
11157 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
11158 if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
11159 route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
11160 }
11161 continue;
11162 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
11163 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
11164 skip_session_order = policy_search_array[i]->session_order + 1;
11165 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
11166 continue;
11167 }
11168
11169 // Passed all tests, found a match
11170 matched_policy = policy_search_array[i];
11171 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
11172 break;
11173 }
11174 }
11175 }
11176
11177 if (route_rule_id_count == 1) {
11178 *return_route_rule_id = route_rule_id_array[0];
11179 } else if (route_rule_id_count > 1) {
11180 *return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11181 }
11182
11183 return matched_policy;
11184 }
11185
11186 static inline bool
necp_output_bypass(struct mbuf * packet)11187 necp_output_bypass(struct mbuf *packet)
11188 {
11189 if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
11190 return true;
11191 }
11192 if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
11193 return true;
11194 }
11195 if (necp_is_intcoproc(NULL, packet)) {
11196 return true;
11197 }
11198 return false;
11199 }
11200
11201 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)11202 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
11203 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11204 {
11205 struct ip *ip = NULL;
11206 int hlen = sizeof(struct ip);
11207 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11208 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11209 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11210 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11211 u_int16_t protocol = 0;
11212 u_int32_t bound_interface_index = 0;
11213 u_int32_t last_interface_index = 0;
11214 union necp_sockaddr_union local_addr = { };
11215 union necp_sockaddr_union remote_addr = { };
11216 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11217 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11218 u_int16_t pf_tag = 0;
11219
11220 if (result) {
11221 *result = 0;
11222 }
11223
11224 if (result_parameter) {
11225 memset(result_parameter, 0, sizeof(*result_parameter));
11226 }
11227
11228 if (packet == NULL) {
11229 return NECP_KERNEL_POLICY_ID_NONE;
11230 }
11231
11232 socket_policy_id = necp_get_policy_id_from_packet(packet);
11233 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11234 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11235
11236 // Exit early for an empty list
11237 // Don't lock. Possible race condition, but we don't want the performance hit.
11238 if (necp_kernel_ip_output_policies_count == 0 ||
11239 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
11240 if (necp_drop_all_order > 0) {
11241 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11242 if (result) {
11243 if (necp_output_bypass(packet)) {
11244 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11245 } else {
11246 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11247 }
11248 }
11249 }
11250
11251 return matched_policy_id;
11252 }
11253
11254 // Check for loopback exception
11255 if (necp_output_bypass(packet)) {
11256 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11257 if (result) {
11258 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11259 }
11260 return matched_policy_id;
11261 }
11262
11263 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11264
11265 // Process packet to get relevant fields
11266 ip = mtod(packet, struct ip *);
11267 #ifdef _IP_VHL
11268 hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
11269 #else
11270 hlen = ip->ip_hl << 2;
11271 #endif
11272
11273 protocol = ip->ip_p;
11274
11275 if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
11276 (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
11277 ipoa->ipoa_boundif != IFSCOPE_NONE) {
11278 bound_interface_index = ipoa->ipoa_boundif;
11279 }
11280
11281 local_addr.sin.sin_family = AF_INET;
11282 local_addr.sin.sin_len = sizeof(struct sockaddr_in);
11283 memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
11284
11285 remote_addr.sin.sin_family = AF_INET;
11286 remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
11287 memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
11288
11289 switch (protocol) {
11290 case IPPROTO_TCP: {
11291 struct tcphdr th;
11292 if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
11293 m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
11294 SIN(&local_addr)->sin_port = th.th_sport;
11295 SIN(&remote_addr)->sin_port = th.th_dport;
11296 }
11297 break;
11298 }
11299 case IPPROTO_UDP: {
11300 struct udphdr uh;
11301 if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
11302 m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
11303 SIN(&local_addr)->sin_port = uh.uh_sport;
11304 SIN(&remote_addr)->sin_port = uh.uh_dport;
11305 }
11306 break;
11307 }
11308 default: {
11309 SIN(&local_addr)->sin_port = 0;
11310 SIN(&remote_addr)->sin_port = 0;
11311 break;
11312 }
11313 }
11314
11315 // Match packet to policy
11316 lck_rw_lock_shared(&necp_kernel_policy_lock);
11317 u_int32_t route_rule_id = 0;
11318
11319 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11320 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
11321
11322 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);
11323 if (matched_policy) {
11324 matched_policy_id = matched_policy->id;
11325 if (result) {
11326 *result = matched_policy->result;
11327 }
11328
11329 if (result_parameter) {
11330 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11331 }
11332
11333 if (route_rule_id != 0 &&
11334 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11335 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11336 }
11337
11338 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11339 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);
11340 }
11341 } else {
11342 bool drop_all = false;
11343 /*
11344 * Apply drop-all only to packets which have never matched a primary policy (check
11345 * if the packet saved policy id is none or falls within the socket policy id range).
11346 */
11347 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11348 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11349 drop_all = true;
11350 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11351 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11352 }
11353 }
11354 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11355 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11356 if (result) {
11357 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11358 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
11359 }
11360 } else if (route_rule_id != 0 &&
11361 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11362 // If we matched a route rule, mark it
11363 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11364 }
11365 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11366 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);
11367 }
11368 }
11369
11370 lck_rw_done(&necp_kernel_policy_lock);
11371
11372 return matched_policy_id;
11373 }
11374
11375 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)11376 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11377 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11378 {
11379 struct ip6_hdr *ip6 = NULL;
11380 int next = -1;
11381 int offset = 0;
11382 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11383 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11384 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11385 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11386 u_int16_t protocol = 0;
11387 u_int32_t bound_interface_index = 0;
11388 u_int32_t last_interface_index = 0;
11389 union necp_sockaddr_union local_addr = { };
11390 union necp_sockaddr_union remote_addr = { };
11391 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11392 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11393 u_int16_t pf_tag = 0;
11394
11395 if (result) {
11396 *result = 0;
11397 }
11398
11399 if (result_parameter) {
11400 memset(result_parameter, 0, sizeof(*result_parameter));
11401 }
11402
11403 if (packet == NULL) {
11404 return NECP_KERNEL_POLICY_ID_NONE;
11405 }
11406
11407 socket_policy_id = necp_get_policy_id_from_packet(packet);
11408 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11409 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11410
11411 // Exit early for an empty list
11412 // Don't lock. Possible race condition, but we don't want the performance hit.
11413 if (necp_drop_management_order == 0 &&
11414 (necp_kernel_ip_output_policies_count == 0 ||
11415 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11416 if (necp_drop_all_order > 0) {
11417 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11418 if (result) {
11419 if (necp_output_bypass(packet)) {
11420 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11421 } else {
11422 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11423 }
11424 }
11425 }
11426
11427 return matched_policy_id;
11428 }
11429
11430 // Check for loopback exception
11431 if (necp_output_bypass(packet)) {
11432 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11433 if (result) {
11434 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11435 }
11436 return matched_policy_id;
11437 }
11438
11439 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11440
11441 // Process packet to get relevant fields
11442 ip6 = mtod(packet, struct ip6_hdr *);
11443
11444 if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11445 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11446 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11447 bound_interface_index = ip6oa->ip6oa_boundif;
11448 }
11449
11450 SIN6(&local_addr)->sin6_family = AF_INET6;
11451 SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11452 memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11453
11454 SIN6(&remote_addr)->sin6_family = AF_INET6;
11455 SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11456 memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11457
11458 offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11459 if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11460 protocol = next;
11461 switch (protocol) {
11462 case IPPROTO_TCP: {
11463 struct tcphdr th;
11464 if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11465 m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11466 SIN6(&local_addr)->sin6_port = th.th_sport;
11467 SIN6(&remote_addr)->sin6_port = th.th_dport;
11468 }
11469 break;
11470 }
11471 case IPPROTO_UDP: {
11472 struct udphdr uh;
11473 if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11474 m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11475 SIN6(&local_addr)->sin6_port = uh.uh_sport;
11476 SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11477 }
11478 break;
11479 }
11480 default: {
11481 SIN6(&local_addr)->sin6_port = 0;
11482 SIN6(&remote_addr)->sin6_port = 0;
11483 break;
11484 }
11485 }
11486 }
11487
11488 // Match packet to policy
11489 lck_rw_lock_shared(&necp_kernel_policy_lock);
11490 u_int32_t route_rule_id = 0;
11491
11492 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11493 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11494
11495 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);
11496 if (matched_policy) {
11497 matched_policy_id = matched_policy->id;
11498 if (result) {
11499 *result = matched_policy->result;
11500 }
11501
11502 if (result_parameter) {
11503 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11504 }
11505
11506 if (route_rule_id != 0 &&
11507 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11508 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11509 }
11510
11511 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11512 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);
11513 }
11514 } else {
11515 bool drop_all = false;
11516 /*
11517 * Apply drop-all only to packets which have never matched a primary policy (check
11518 * if the packet saved policy id is none or falls within the socket policy id range).
11519 */
11520 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11521 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11522 drop_all = true;
11523 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11524 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11525 }
11526 }
11527 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11528 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11529 if (result) {
11530 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11531 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11532 }
11533 } else if (route_rule_id != 0 &&
11534 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11535 // If we matched a route rule, mark it
11536 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11537 }
11538 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11539 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);
11540 }
11541 }
11542
11543 lck_rw_done(&necp_kernel_policy_lock);
11544
11545 return matched_policy_id;
11546 }
11547
11548 // Utilities
11549 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11550 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11551 {
11552 int cmp = 0;
11553
11554 if (addr == NULL || range_start == NULL || range_end == NULL) {
11555 return FALSE;
11556 }
11557
11558 /* Must be greater than or equal to start */
11559 cmp = necp_addr_compare(addr, range_start, 1);
11560 if (cmp != 0 && cmp != 1) {
11561 return FALSE;
11562 }
11563
11564 /* Must be less than or equal to end */
11565 cmp = necp_addr_compare(addr, range_end, 1);
11566 if (cmp != 0 && cmp != -1) {
11567 return FALSE;
11568 }
11569
11570 return TRUE;
11571 }
11572
11573 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)11574 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11575 {
11576 int cmp = 0;
11577
11578 if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11579 return FALSE;
11580 }
11581
11582 /* Must be greater than or equal to start */
11583 cmp = necp_addr_compare(inner_range_start, range_start, 1);
11584 if (cmp != 0 && cmp != 1) {
11585 return FALSE;
11586 }
11587
11588 /* Must be less than or equal to end */
11589 cmp = necp_addr_compare(inner_range_end, range_end, 1);
11590 if (cmp != 0 && cmp != -1) {
11591 return FALSE;
11592 }
11593
11594 return TRUE;
11595 }
11596
11597 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11598 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11599 {
11600 if (addr == NULL || subnet_addr == NULL) {
11601 return FALSE;
11602 }
11603
11604 if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11605 return FALSE;
11606 }
11607
11608 switch (addr->sa_family) {
11609 case AF_INET: {
11610 if (satosin(subnet_addr)->sin_port != 0 &&
11611 satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11612 return FALSE;
11613 }
11614 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11615 }
11616 case AF_INET6: {
11617 if (satosin6(subnet_addr)->sin6_port != 0 &&
11618 satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11619 return FALSE;
11620 }
11621 if (satosin6(addr)->sin6_scope_id &&
11622 satosin6(subnet_addr)->sin6_scope_id &&
11623 satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11624 return FALSE;
11625 }
11626 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11627 }
11628 default: {
11629 return FALSE;
11630 }
11631 }
11632
11633 return FALSE;
11634 }
11635
11636 /*
11637 * Return values:
11638 * -1: sa1 < sa2
11639 * 0: sa1 == sa2
11640 * 1: sa1 > sa2
11641 * 2: Not comparable or error
11642 */
11643 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11644 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11645 {
11646 int result = 0;
11647 int port_result = 0;
11648
11649 if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11650 return 2;
11651 }
11652
11653 if (sa1->sa_len == 0) {
11654 return 0;
11655 }
11656
11657 switch (sa1->sa_family) {
11658 case AF_INET: {
11659 if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11660 return 2;
11661 }
11662
11663 result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11664
11665 if (check_port) {
11666 if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11667 port_result = -1;
11668 } else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11669 port_result = 1;
11670 }
11671
11672 if (result == 0) {
11673 result = port_result;
11674 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11675 return 2;
11676 }
11677 }
11678
11679 break;
11680 }
11681 case AF_INET6: {
11682 if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11683 return 2;
11684 }
11685
11686 if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11687 return 2;
11688 }
11689
11690 result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11691
11692 if (check_port) {
11693 if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11694 port_result = -1;
11695 } else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11696 port_result = 1;
11697 }
11698
11699 if (result == 0) {
11700 result = port_result;
11701 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11702 return 2;
11703 }
11704 }
11705
11706 break;
11707 }
11708 default: {
11709 result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11710 break;
11711 }
11712 }
11713
11714 if (result < 0) {
11715 result = (-1);
11716 } else if (result > 0) {
11717 result = (1);
11718 }
11719
11720 return result;
11721 }
11722
11723 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11724 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11725 {
11726 u_int8_t mask;
11727
11728 /* Handle null pointers */
11729 if (p1 == NULL || p2 == NULL) {
11730 return p1 == p2;
11731 }
11732
11733 while (bits >= 8) {
11734 if (*p1++ != *p2++) {
11735 return FALSE;
11736 }
11737 bits -= 8;
11738 }
11739
11740 if (bits > 0) {
11741 mask = ~((1 << (8 - bits)) - 1);
11742 if ((*p1 & mask) != (*p2 & mask)) {
11743 return FALSE;
11744 }
11745 }
11746 return TRUE;
11747 }
11748
11749 static bool
necp_addr_is_empty(struct sockaddr * addr)11750 necp_addr_is_empty(struct sockaddr *addr)
11751 {
11752 if (addr == NULL) {
11753 return TRUE;
11754 }
11755
11756 if (addr->sa_len == 0) {
11757 return TRUE;
11758 }
11759
11760 switch (addr->sa_family) {
11761 case AF_INET: {
11762 static struct sockaddr_in ipv4_empty_address = {
11763 .sin_len = sizeof(struct sockaddr_in),
11764 .sin_family = AF_INET,
11765 .sin_port = 0,
11766 .sin_addr = { .s_addr = 0 }, // 0.0.0.0
11767 .sin_zero = {0},
11768 };
11769 if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11770 return TRUE;
11771 } else {
11772 return FALSE;
11773 }
11774 }
11775 case AF_INET6: {
11776 static struct sockaddr_in6 ipv6_empty_address = {
11777 .sin6_len = sizeof(struct sockaddr_in6),
11778 .sin6_family = AF_INET6,
11779 .sin6_port = 0,
11780 .sin6_flowinfo = 0,
11781 .sin6_addr = IN6ADDR_ANY_INIT, // ::
11782 .sin6_scope_id = 0,
11783 };
11784 if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11785 return TRUE;
11786 } else {
11787 return FALSE;
11788 }
11789 }
11790 default:
11791 return FALSE;
11792 }
11793
11794 return FALSE;
11795 }
11796
11797 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)11798 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)
11799 {
11800 bool qos_marking = FALSE;
11801 int exception_index = 0;
11802 struct necp_route_rule *route_rule = NULL;
11803
11804 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11805 if (route_rule == NULL) {
11806 qos_marking = FALSE;
11807 goto done;
11808 }
11809
11810 if (route_rule->match_netagent_id != 0) {
11811 if (netagent_array == NULL || netagent_array_count == 0) {
11812 // No agents, ignore rule
11813 goto done;
11814 }
11815 bool found_match = FALSE;
11816 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11817 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11818 found_match = TRUE;
11819 break;
11820 }
11821 }
11822 if (!found_match) {
11823 // Agents don't match, ignore rule
11824 goto done;
11825 }
11826 }
11827
11828 qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11829
11830 if (ifp == NULL) {
11831 goto done;
11832 }
11833
11834 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11835 if (route_rule->exception_if_indices[exception_index] == 0) {
11836 break;
11837 }
11838 if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
11839 continue;
11840 }
11841 if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
11842 qos_marking = TRUE;
11843 if (necp_debug > 2) {
11844 NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
11845 route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
11846 }
11847 goto done;
11848 }
11849 }
11850
11851 if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
11852 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
11853 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
11854 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
11855 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
11856 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
11857 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
11858 qos_marking = TRUE;
11859 if (necp_debug > 2) {
11860 NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d for Rule %d Allowed %d",
11861 route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
11862 route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action, route_rule_id, qos_marking);
11863 }
11864 goto done;
11865 }
11866 done:
11867 if (necp_debug > 1) {
11868 NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
11869 route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
11870 }
11871 return qos_marking;
11872 }
11873
11874 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)11875 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)
11876 {
11877 bool new_qos_marking = old_qos_marking;
11878 struct ifnet *ifp = interface;
11879
11880 if (net_qos_policy_restricted == 0) {
11881 return new_qos_marking;
11882 }
11883
11884 /*
11885 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
11886 */
11887 if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
11888 return new_qos_marking;
11889 }
11890
11891 lck_rw_lock_shared(&necp_kernel_policy_lock);
11892
11893 if (ifp == NULL && route != NULL) {
11894 ifp = route->rt_ifp;
11895 }
11896 /*
11897 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
11898 */
11899 if (ifp == NULL || route_rule_id == 0) {
11900 new_qos_marking = FALSE;
11901 goto done;
11902 }
11903
11904 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11905 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11906 if (aggregate_route_rule != NULL) {
11907 int index = 0;
11908 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11909 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11910 if (sub_route_rule_id == 0) {
11911 break;
11912 }
11913 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
11914 if (new_qos_marking == TRUE) {
11915 break;
11916 }
11917 }
11918 }
11919 } else {
11920 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
11921 }
11922 /*
11923 * Now that we have an interface we remember the gencount
11924 */
11925 *qos_marking_gencount = necp_kernel_socket_policies_gencount;
11926
11927 done:
11928 lck_rw_done(&necp_kernel_policy_lock);
11929 return new_qos_marking;
11930 }
11931
11932 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)11933 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11934 {
11935 bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11936
11937 if (net_qos_policy_restricted == 0) {
11938 return;
11939 }
11940 if (inp->inp_socket == NULL) {
11941 return;
11942 }
11943 if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11944 return;
11945 }
11946
11947 qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
11948
11949 if (qos_marking == TRUE) {
11950 inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
11951 } else {
11952 inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
11953 }
11954 }
11955
11956 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)11957 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
11958 {
11959 if (ifp != NULL &&
11960 (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11961 ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11962 return true;
11963 }
11964 if (delegated_ifp != NULL &&
11965 (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11966 delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11967 return true;
11968 }
11969 return false;
11970 }
11971
11972 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)11973 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,
11974 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11975 {
11976 bool default_is_allowed = TRUE;
11977 u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
11978 int exception_index = 0;
11979 struct ifnet *delegated_ifp = NULL;
11980 struct necp_route_rule *route_rule = NULL;
11981
11982 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11983 if (route_rule == NULL) {
11984 return TRUE;
11985 }
11986
11987 if (route_rule->match_netagent_id != 0) {
11988 if (netagent_array == NULL || netagent_array_count == 0) {
11989 // No agents, ignore rule
11990 return TRUE;
11991 }
11992 bool found_match = FALSE;
11993 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11994 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11995 found_match = TRUE;
11996 break;
11997 }
11998 }
11999 if (!found_match) {
12000 // Agents don't match, ignore rule
12001 return TRUE;
12002 }
12003 }
12004
12005 default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
12006 if (ifp == NULL && route != NULL) {
12007 ifp = route->rt_ifp;
12008 }
12009 if (ifp == NULL) {
12010 if (necp_debug > 1 && !default_is_allowed) {
12011 NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12012 }
12013 return default_is_allowed;
12014 }
12015
12016 delegated_ifp = ifp->if_delegated.ifp;
12017 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12018 if (route_rule->exception_if_indices[exception_index] == 0) {
12019 break;
12020 }
12021 if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
12022 (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
12023 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12024 const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
12025 if (necp_debug > 1 && lqm_abort) {
12026 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
12027 route_rule->exception_if_indices[exception_index], route_rule_id);
12028 }
12029 return false;
12030 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
12031 if (necp_debug > 1) {
12032 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));
12033 }
12034 if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
12035 *interface_type_denied = route_rule->effective_type;
12036 }
12037 return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
12038 }
12039 }
12040 }
12041
12042 if (IFNET_IS_CELLULAR(ifp)) {
12043 if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12044 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12045 if (interface_type_denied != NULL) {
12046 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12047 if (route_rule->effective_type != 0) {
12048 *interface_type_denied = route_rule->effective_type;
12049 }
12050 }
12051 // Mark aggregate action as deny
12052 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12053 }
12054 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
12055 if (interface_type_denied != NULL) {
12056 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12057 if (route_rule->effective_type != 0) {
12058 *interface_type_denied = route_rule->effective_type;
12059 }
12060 }
12061 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12062 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12063 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
12064 // Deny wins if there is a conflict
12065 type_aggregate_action = route_rule->cellular_action;
12066 }
12067 }
12068 }
12069
12070 if (IFNET_IS_WIFI(ifp)) {
12071 if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12072 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12073 if (interface_type_denied != NULL) {
12074 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12075 if (route_rule->effective_type != 0) {
12076 *interface_type_denied = route_rule->effective_type;
12077 }
12078 }
12079 // Mark aggregate action as deny
12080 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12081 }
12082 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
12083 if (interface_type_denied != NULL) {
12084 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12085 if (route_rule->effective_type != 0) {
12086 *interface_type_denied = route_rule->effective_type;
12087 }
12088 }
12089 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12090 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12091 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
12092 // Deny wins if there is a conflict
12093 type_aggregate_action = route_rule->wifi_action;
12094 }
12095 }
12096 }
12097
12098 if (IFNET_IS_COMPANION_LINK(ifp) ||
12099 (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
12100 if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12101 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12102 if (interface_type_denied != NULL) {
12103 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12104 if (route_rule->effective_type != 0) {
12105 *interface_type_denied = route_rule->effective_type;
12106 }
12107 }
12108 // Mark aggregate action as deny
12109 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12110 }
12111 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
12112 if (interface_type_denied != NULL) {
12113 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12114 if (route_rule->effective_type != 0) {
12115 *interface_type_denied = route_rule->effective_type;
12116 }
12117 }
12118 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12119 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12120 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
12121 // Deny wins if there is a conflict
12122 type_aggregate_action = route_rule->companion_action;
12123 }
12124 }
12125 }
12126
12127 if (IFNET_IS_WIRED(ifp)) {
12128 if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12129 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12130 if (interface_type_denied != NULL) {
12131 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12132 if (route_rule->effective_type != 0) {
12133 *interface_type_denied = route_rule->effective_type;
12134 }
12135 }
12136 // Mark aggregate action as deny
12137 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12138 }
12139 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
12140 if (interface_type_denied != NULL) {
12141 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12142 if (route_rule->effective_type != 0) {
12143 *interface_type_denied = route_rule->effective_type;
12144 }
12145 }
12146 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12147 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12148 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
12149 // Deny wins if there is a conflict
12150 type_aggregate_action = route_rule->wired_action;
12151 }
12152 }
12153 }
12154
12155 if (IFNET_IS_EXPENSIVE(ifp)) {
12156 if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12157 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12158 // Mark aggregate action as deny
12159 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12160 }
12161 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
12162 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12163 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12164 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
12165 // Deny wins if there is a conflict
12166 type_aggregate_action = route_rule->expensive_action;
12167 }
12168 }
12169 }
12170
12171 if (IFNET_IS_CONSTRAINED(ifp)) {
12172 if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12173 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12174 // Mark aggregate action as deny
12175 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12176 }
12177 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
12178 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12179 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12180 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
12181 // Deny wins if there is a conflict
12182 type_aggregate_action = route_rule->constrained_action;
12183 }
12184 }
12185 }
12186
12187 if (IFNET_IS_VPN(ifp)) {
12188 if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12189 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12190 // Mark aggregate action as deny
12191 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12192 }
12193 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
12194 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12195 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12196 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
12197 // Deny wins if there is a conflict
12198 type_aggregate_action = route_rule->vpn_action;
12199 }
12200 }
12201 }
12202
12203 if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
12204 if (necp_debug > 1) {
12205 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));
12206 }
12207 return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
12208 }
12209
12210 if (necp_debug > 1 && !default_is_allowed) {
12211 NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12212 }
12213 return default_is_allowed;
12214 }
12215
12216 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)12217 necp_proc_is_allowed_on_management_interface(proc_t proc)
12218 {
12219 bool allowed = false;
12220 const task_t __single task = proc_task(proc);
12221
12222 if (task != NULL) {
12223 if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
12224 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
12225 #if DEBUG || DEVELOPMENT
12226 || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
12227 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
12228 #endif /* DEBUG || DEVELOPMENT */
12229 ) {
12230 allowed = true;
12231 }
12232 }
12233 return allowed;
12234 }
12235
12236 __attribute__((noinline))
12237 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)12238 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12239 {
12240 char buf[128];
12241
12242 if (inp != NULL) {
12243 inp_snprintf_tuple(inp, buf, sizeof(buf));
12244 } else {
12245 *buf = 0;
12246 }
12247 os_log(OS_LOG_DEFAULT,
12248 "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
12249 proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
12250 proc != NULL ? proc_getpid(proc) : proc_selfpid(),
12251 inp != NULL ? buf : "",
12252 ifp->if_xname);
12253 }
12254
12255 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)12256 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12257 {
12258 if (if_management_interface_check_needed == false) {
12259 return true;
12260 }
12261 if (necp_drop_management_order == 0) {
12262 return true;
12263 }
12264 if (ifp == NULL && route != NULL) {
12265 ifp = route->rt_ifp;
12266 }
12267 if (ifp == NULL) {
12268 return true;
12269 }
12270
12271 if (IFNET_IS_MANAGEMENT(ifp)) {
12272 bool allowed = true;
12273
12274 if (inp != NULL) {
12275 /*
12276 * The entitlement check is already performed for socket flows
12277 */
12278 allowed = INP_MANAGEMENT_ALLOWED(inp);
12279 } else if (proc != NULL) {
12280 allowed = necp_proc_is_allowed_on_management_interface(proc);
12281 }
12282 if (__improbable(if_management_verbose > 1 && allowed == false)) {
12283 necp_log_interface_not_allowed(ifp, proc, inp);
12284 }
12285 return allowed;
12286 }
12287 return true;
12288 }
12289
12290 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)12291 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,
12292 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12293 {
12294 if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
12295 if (necp_debug > 1) {
12296 NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
12297 }
12298 return TRUE;
12299 }
12300
12301 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12302 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12303 if (aggregate_route_rule != NULL) {
12304 int index = 0;
12305 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12306 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12307 if (sub_route_rule_id == 0) {
12308 break;
12309 }
12310 if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
12311 return FALSE;
12312 }
12313 }
12314 }
12315 } else {
12316 return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
12317 }
12318
12319 return TRUE;
12320 }
12321
12322 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)12323 necp_route_rule_matches_agents(u_int32_t route_rule_id)
12324 {
12325 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12326 if (route_rule == NULL) {
12327 return false;
12328 }
12329
12330 return route_rule->match_netagent_id != 0;
12331 }
12332
12333 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)12334 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)
12335 {
12336 if (remove == NULL) {
12337 return 0;
12338 }
12339
12340 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12341 if (route_rule == NULL) {
12342 return 0;
12343 }
12344
12345 // No netagent, skip
12346 if (route_rule->netagent_id == 0) {
12347 return 0;
12348 }
12349
12350 if (route_rule->match_netagent_id != 0) {
12351 if (netagent_array == NULL || netagent_array_count == 0) {
12352 // No agents, ignore rule
12353 return 0;
12354 }
12355 bool found_match = FALSE;
12356 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12357 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12358 found_match = TRUE;
12359 break;
12360 }
12361 }
12362 if (!found_match) {
12363 // Agents don't match, ignore rule
12364 return 0;
12365 }
12366 }
12367
12368 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12369 if (ifp == NULL) {
12370 // No interface, apply the default action
12371 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12372 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12373 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12374 return route_rule->netagent_id;
12375 }
12376 return 0;
12377 }
12378
12379 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12380 if (route_rule->exception_if_indices[exception_index] == 0) {
12381 break;
12382 }
12383 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12384 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12385 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12386 route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12387 *remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12388 return route_rule->netagent_id;
12389 }
12390 return 0;
12391 }
12392 }
12393
12394 if (ifp->if_type == IFT_CELLULAR &&
12395 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12396 if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12397 route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12398 *remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12399 return route_rule->netagent_id;
12400 }
12401 return 0;
12402 }
12403
12404 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12405 route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12406 if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12407 route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12408 *remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12409 return route_rule->netagent_id;
12410 }
12411 return 0;
12412 }
12413
12414 if (IFNET_IS_COMPANION_LINK(ifp) &&
12415 route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12416 if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12417 route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12418 *remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12419 return route_rule->netagent_id;
12420 }
12421 return 0;
12422 }
12423
12424 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12425 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12426 if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12427 route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12428 *remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12429 return route_rule->netagent_id;
12430 }
12431 return 0;
12432 }
12433
12434 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12435 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12436 if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12437 route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12438 *remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12439 return route_rule->netagent_id;
12440 }
12441 return 0;
12442 }
12443
12444 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12445 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12446 if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12447 route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12448 *remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12449 return route_rule->netagent_id;
12450 }
12451 return 0;
12452 }
12453
12454 if (ifp->if_xflags & IFXF_IS_VPN &&
12455 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12456 if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12457 route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12458 *remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12459 return route_rule->netagent_id;
12460 }
12461 return 0;
12462 }
12463
12464 // No more specific case matched, apply the default action
12465 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12466 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12467 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12468 return route_rule->netagent_id;
12469 }
12470
12471 return 0;
12472 }
12473
12474 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)12475 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)
12476 {
12477 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12478 if (route_rule == NULL) {
12479 return 0;
12480 }
12481
12482 // No control unit, skip
12483 if (route_rule->control_unit == 0) {
12484 return 0;
12485 }
12486
12487 if (route_rule->match_netagent_id != 0) {
12488 if (netagent_array == NULL || netagent_array_count == 0) {
12489 // No agents, ignore rule
12490 return 0;
12491 }
12492 bool found_match = FALSE;
12493 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12494 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12495 found_match = TRUE;
12496 break;
12497 }
12498 }
12499 if (!found_match) {
12500 // Agents don't match, ignore rule
12501 return 0;
12502 }
12503 }
12504
12505 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12506 if (ifp == NULL) {
12507 // No interface, apply the default action
12508 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12509 return route_rule->control_unit;
12510 }
12511 return 0;
12512 }
12513
12514 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12515 if (route_rule->exception_if_indices[exception_index] == 0) {
12516 break;
12517 }
12518 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12519 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12520 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12521 return route_rule->control_unit;
12522 }
12523 return 0;
12524 }
12525 }
12526
12527 if (ifp->if_type == IFT_CELLULAR &&
12528 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12529 if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12530 return route_rule->control_unit;
12531 }
12532 return 0;
12533 }
12534
12535 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12536 route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12537 if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12538 return route_rule->control_unit;
12539 }
12540 return 0;
12541 }
12542
12543 if (IFNET_IS_COMPANION_LINK(ifp) &&
12544 route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12545 if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12546 return route_rule->control_unit;
12547 }
12548 return 0;
12549 }
12550
12551 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12552 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12553 if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12554 return route_rule->control_unit;
12555 }
12556 return 0;
12557 }
12558
12559 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12560 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12561 if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12562 return route_rule->control_unit;
12563 }
12564 return 0;
12565 }
12566
12567 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12568 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12569 if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12570 return route_rule->control_unit;
12571 }
12572 return 0;
12573 }
12574
12575 if (ifp->if_xflags & IFXF_IS_VPN &&
12576 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12577 if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12578 return route_rule->control_unit;
12579 }
12580 return 0;
12581 }
12582
12583 // No more specific case matched, apply the default action
12584 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12585 return route_rule->control_unit;
12586 }
12587 return 0;
12588 }
12589
12590 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)12591 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,
12592 u_int32_t *flow_divert_aggregate_unit)
12593 {
12594 if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12595 return 0;
12596 }
12597
12598 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12599 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12600 if (aggregate_route_rule != NULL) {
12601 int index = 0;
12602 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12603 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12604 if (sub_route_rule_id == 0) {
12605 break;
12606 }
12607 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12608 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12609 // For transparent proxies, accumulate the control unit and continue to the next route rule
12610 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12611 continue;
12612 }
12613
12614 if (control_unit != 0) {
12615 return control_unit;
12616 }
12617 }
12618 }
12619 } else {
12620 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12621 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12622 // For transparent proxies, accumulate the control unit and let the caller continue
12623 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12624 return 0;
12625 }
12626 return control_unit;
12627 }
12628
12629 return 0;
12630 }
12631
12632 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12633 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12634 {
12635 bool is_allowed = true;
12636 u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12637 if (route_rule_id != 0 &&
12638 interface != NULL) {
12639 lck_rw_lock_shared(&necp_kernel_policy_lock);
12640 is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
12641 lck_rw_done(&necp_kernel_policy_lock);
12642 }
12643 return is_allowed;
12644 }
12645
12646 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12647 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12648 {
12649 size_t netagent_cursor;
12650 for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12651 struct necp_uuid_id_mapping *mapping = NULL;
12652 u_int32_t netagent_id = netagent_ids[netagent_cursor];
12653 if (netagent_id == 0) {
12654 continue;
12655 }
12656 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
12657 if (mapping != NULL) {
12658 u_int32_t agent_flags = 0;
12659 agent_flags = netagent_get_flags(mapping->uuid);
12660 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12661 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12662 continue;
12663 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12664 return FALSE;
12665 }
12666 }
12667 }
12668 }
12669 return TRUE;
12670 }
12671
12672 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12673 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12674 {
12675 bool allowed_to_receive = TRUE;
12676
12677 if (pf_tag == PF_TAG_ID_STACK_DROP &&
12678 (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12679 allowed_to_receive = FALSE;
12680 }
12681
12682 return allowed_to_receive;
12683 }
12684
12685 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)12686 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)
12687 {
12688 u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12689 bool allowed_to_receive = TRUE;
12690 struct necp_socket_info info = {};
12691 u_int32_t flowhash = 0;
12692 necp_kernel_policy_result service_action = 0;
12693 necp_kernel_policy_service service = { 0, 0 };
12694 u_int32_t route_rule_id = 0;
12695 struct rtentry *route = NULL;
12696 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12697 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12698 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12699 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12700 proc_t __single socket_proc = NULL;
12701 necp_kernel_policy_filter filter_control_unit = 0;
12702 u_int32_t pass_flags = 0;
12703 u_int32_t flow_divert_aggregate_unit = 0;
12704 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12705 int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12706
12707 memset(&netagent_ids, 0, sizeof(netagent_ids));
12708
12709 if (return_policy_id) {
12710 *return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12711 }
12712 if (return_skip_policy_id) {
12713 *return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12714 }
12715 if (return_route_rule_id) {
12716 *return_route_rule_id = 0;
12717 }
12718 if (return_pass_flags) {
12719 *return_pass_flags = 0;
12720 }
12721
12722 if (inp == NULL) {
12723 goto done;
12724 }
12725
12726 route = inp->inp_route.ro_rt;
12727
12728 struct socket *so = inp->inp_socket;
12729
12730 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12731
12732 // Don't lock. Possible race condition, but we don't want the performance hit.
12733 if (necp_drop_management_order == 0 &&
12734 (necp_kernel_socket_policies_count == 0 ||
12735 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12736 if (necp_drop_all_order > 0 || drop_order > 0) {
12737 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12738 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12739 allowed_to_receive = TRUE;
12740 } else {
12741 allowed_to_receive = FALSE;
12742 }
12743 }
12744 goto done;
12745 }
12746
12747 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
12748 if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12749 bool policies_have_changed = FALSE;
12750 bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12751 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12752 policies_have_changed = TRUE;
12753 } else {
12754 if (inp->inp_policyresult.results.route_rule_id != 0) {
12755 lck_rw_lock_shared(&necp_kernel_policy_lock);
12756 if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
12757 route_allowed = FALSE;
12758 }
12759 lck_rw_done(&necp_kernel_policy_lock);
12760 }
12761 }
12762
12763 if (!policies_have_changed) {
12764 if (debug) {
12765 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);
12766 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12767 }
12768
12769 if (!route_allowed ||
12770 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12771 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12772 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12773 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12774 allowed_to_receive = FALSE;
12775 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);
12776 } else {
12777 if (return_policy_id) {
12778 *return_policy_id = inp->inp_policyresult.policy_id;
12779 }
12780 if (return_skip_policy_id) {
12781 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12782 }
12783 if (return_route_rule_id) {
12784 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12785 }
12786 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12787 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12788 }
12789 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);
12790 }
12791 goto done;
12792 }
12793 }
12794
12795 // Check for loopback exception
12796 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12797 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12798 allowed_to_receive = FALSE;
12799 goto done;
12800 }
12801 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
12802 allowed_to_receive = TRUE;
12803 goto done;
12804 }
12805
12806 // Actually calculate policy result
12807 lck_rw_lock_shared(&necp_kernel_policy_lock);
12808 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);
12809
12810 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12811 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
12812
12813 flowhash = necp_socket_calc_flowhash_locked(&info);
12814 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12815 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
12816 inp->inp_policyresult.flowhash == flowhash) {
12817 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12818 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12819 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12820 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
12821 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12822 (inp->inp_policyresult.results.route_rule_id != 0 &&
12823 !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
12824 allowed_to_receive = FALSE;
12825 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);
12826 } else {
12827 if (return_policy_id) {
12828 *return_policy_id = inp->inp_policyresult.policy_id;
12829 }
12830 if (return_route_rule_id) {
12831 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12832 }
12833 if (return_skip_policy_id) {
12834 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12835 }
12836 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12837 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12838 }
12839 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12840 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",
12841 inp->inp_socket, info.bound_interface_index, info.protocol,
12842 inp->inp_policyresult.policy_id,
12843 inp->inp_policyresult.skip_policy_id,
12844 inp->inp_policyresult.results.result,
12845 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
12846 }
12847 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
12848 return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12849 }
12850 lck_rw_done(&necp_kernel_policy_lock);
12851 goto done;
12852 }
12853
12854 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
12855 size_t route_rule_id_array_count = 0;
12856 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
12857 struct necp_kernel_socket_policy *matched_policy =
12858 necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
12859 &info,
12860 &filter_control_unit,
12861 route_rule_id_array,
12862 &route_rule_id_array_count,
12863 MAX_AGGREGATE_ROUTE_RULES,
12864 &service_action,
12865 &service,
12866 netagent_ids,
12867 NECP_MAX_NETAGENTS,
12868 NULL,
12869 0,
12870 NULL,
12871 0,
12872 effective_proc,
12873 pf_tag,
12874 return_skip_policy_id,
12875 inp->inp_route.ro_rt,
12876 &drop_dest_policy_result,
12877 &drop_all_bypass,
12878 &flow_divert_aggregate_unit,
12879 so,
12880 debug);
12881
12882 // Check for loopback exception again after the policy match
12883 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
12884 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
12885 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
12886 // If policies haven't changed since last evaluation, do not update filter result in order to
12887 // preserve the very first filter result for the socket. Otherwise, update the filter result to
12888 // allow content filter to detect and drop pre-existing flows.
12889 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12890 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12891 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12892 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12893 }
12894 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12895 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12896 }
12897 allowed_to_receive = TRUE;
12898 lck_rw_done(&necp_kernel_policy_lock);
12899
12900 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);
12901 goto done;
12902 }
12903
12904 if (info.protocol != IPPROTO_UDP) {
12905 goto skip_agent_check;
12906 }
12907
12908 // Verify netagents
12909 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
12910 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12911 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);
12912 }
12913
12914 // Mark socket as a drop if required agent is not active
12915 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12916 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12917 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12918 inp->inp_policyresult.flowhash = flowhash;
12919 inp->inp_policyresult.results.filter_control_unit = 0;
12920 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
12921 inp->inp_policyresult.results.route_rule_id = 0;
12922 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
12923
12924 // Unlock
12925 allowed_to_receive = FALSE;
12926 lck_rw_done(&necp_kernel_policy_lock);
12927
12928 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);
12929
12930 goto done;
12931 }
12932
12933 skip_agent_check:
12934
12935 if (route_rule_id_array_count == 1) {
12936 route_rule_id = route_rule_id_array[0];
12937 } else if (route_rule_id_array_count > 1) {
12938 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
12939 }
12940
12941 bool send_local_network_denied_event = false;
12942 if (matched_policy != NULL) {
12943 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
12944 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
12945 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
12946 // Trigger the event that we dropped due to a local network policy
12947 send_local_network_denied_event = true;
12948 }
12949
12950 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
12951 matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12952 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12953 matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
12954 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12955 (route_rule_id != 0 &&
12956 !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
12957 !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
12958 allowed_to_receive = FALSE;
12959 } else {
12960 if (return_policy_id) {
12961 *return_policy_id = matched_policy->id;
12962 }
12963 if (return_route_rule_id) {
12964 *return_route_rule_id = route_rule_id;
12965 }
12966 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
12967 pass_flags = matched_policy->result_parameter.pass_flags;
12968 }
12969 // If policies haven't changed since last evaluation, do not update filter result in order to
12970 // preserve the very first filter result for the socket. Otherwise, update the filter result to
12971 // allow content filter to detect and drop pre-existing flows.
12972 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12973 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12974 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12975 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12976 }
12977 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12978 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12979 }
12980 }
12981
12982 if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
12983 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>",
12984 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);
12985 }
12986 } else {
12987 bool drop_all = false;
12988 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
12989 drop_all = true;
12990 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
12991 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
12992 }
12993 }
12994 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
12995 allowed_to_receive = FALSE;
12996 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
12997 } else {
12998 if (return_policy_id) {
12999 *return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13000 }
13001 if (return_route_rule_id) {
13002 *return_route_rule_id = route_rule_id;
13003 }
13004
13005 // If policies haven't changed since last evaluation, do not update filter result in order to
13006 // preserve the very first filter result for the socket. Otherwise, update the filter result to
13007 // allow content filter to detect and drop pre-existing flows.
13008 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
13009 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
13010 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13011 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13012 }
13013 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13014 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13015 }
13016 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);
13017 }
13018 }
13019
13020 if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
13021 allowed_to_receive = FALSE;
13022 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
13023 }
13024
13025 lck_rw_done(&necp_kernel_policy_lock);
13026
13027 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
13028 inp->inp_policyresult.network_denied_notifies++;
13029 #if defined(XNU_TARGET_OS_OSX)
13030 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
13031 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13032 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13033 NETPOLICY_NETWORKTYPE_LOCAL);
13034 #else
13035 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13036 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13037 NETPOLICY_NETWORKTYPE_LOCAL);
13038 #endif
13039 }
13040
13041 done:
13042 if (return_pass_flags != NULL) {
13043 *return_pass_flags = pass_flags;
13044 }
13045
13046 if (pf_tag != 0 && allowed_to_receive) {
13047 allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
13048 }
13049
13050 if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
13051 soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
13052 }
13053
13054 if (socket_proc) {
13055 proc_rele(socket_proc);
13056 }
13057
13058 return allowed_to_receive;
13059 }
13060
13061 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)13062 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)
13063 {
13064 struct sockaddr_in local = {};
13065 struct sockaddr_in remote = {};
13066 local.sin_family = remote.sin_family = AF_INET;
13067 local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
13068 local.sin_port = local_port;
13069 remote.sin_port = remote_port;
13070 memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
13071 memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
13072
13073 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13074 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13075 }
13076
13077 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)13078 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)
13079 {
13080 struct sockaddr_in6 local = {};
13081 struct sockaddr_in6 remote = {};
13082 local.sin6_family = remote.sin6_family = AF_INET6;
13083 local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
13084 local.sin6_port = local_port;
13085 remote.sin6_port = remote_port;
13086 memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
13087 memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
13088
13089 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13090 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13091 }
13092
13093 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)13094 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,
13095 u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13096 {
13097 return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
13098 return_policy_id, return_route_rule_id,
13099 return_skip_policy_id, return_pass_flags);
13100 }
13101
13102 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)13103 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
13104 necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
13105 {
13106 if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
13107 return EINVAL;
13108 }
13109
13110 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13111 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
13112 policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
13113 }
13114
13115 // Mark ID for Pass and IP Tunnel
13116 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13117 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13118 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
13119 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
13120 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13121 } else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
13122 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
13123 // This case is same as a PASS
13124 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13125 } else {
13126 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13127 }
13128 packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
13129 if (route_rule_id != 0) {
13130 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
13131 } else {
13132 packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13133 }
13134 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);
13135
13136 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13137 skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13138 // Only mark the skip policy if it is a valid policy ID
13139 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13140 } else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13141 inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13142 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13143 } else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
13144 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
13145 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
13146 // See necp_get_skip_policy_id_from_packet() and
13147 // necp_packet_should_skip_filters().
13148 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13149 } else {
13150 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13151 }
13152
13153 if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
13154 ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
13155 m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
13156 }
13157
13158 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13159 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
13160 packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
13161 }
13162
13163 return 0;
13164 }
13165
13166 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)13167 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
13168 {
13169 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13170 return EINVAL;
13171 }
13172
13173 // Mark ID for Pass and IP Tunnel
13174 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13175 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13176 } else {
13177 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13178 }
13179
13180 return 0;
13181 }
13182
13183 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)13184 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
13185 {
13186 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13187 return EINVAL;
13188 }
13189
13190 // Mark ID for Pass and IP Tunnel
13191 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13192 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13193 } else {
13194 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13195 }
13196
13197 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13198 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13199 } else {
13200 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13201 }
13202 return 0;
13203 }
13204
13205 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)13206 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
13207 {
13208 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13209 return EINVAL;
13210 }
13211
13212 // Mark ID for Pass and IP Tunnel
13213 if (interface != NULL) {
13214 packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
13215 }
13216
13217 return 0;
13218 }
13219
13220 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)13221 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
13222 {
13223 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13224 return EINVAL;
13225 }
13226
13227 if (is_keepalive) {
13228 packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
13229 } else {
13230 packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
13231 }
13232
13233 return 0;
13234 }
13235
13236 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)13237 necp_get_policy_id_from_packet(struct mbuf *packet)
13238 {
13239 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13240 return NECP_KERNEL_POLICY_ID_NONE;
13241 }
13242
13243 return packet->m_pkthdr.necp_mtag.necp_policy_id;
13244 }
13245
13246 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)13247 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
13248 {
13249 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13250 return NECP_KERNEL_POLICY_ID_NONE;
13251 }
13252
13253 // Check for overloaded value. See necp_mark_packet_from_socket().
13254 if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
13255 return NECP_KERNEL_POLICY_ID_NONE;
13256 }
13257
13258 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
13259 }
13260
13261 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)13262 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
13263 {
13264 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13265 return 0;
13266 }
13267
13268 return m_pftag(packet)->pftag_tag;
13269 }
13270
13271 bool
necp_packet_should_skip_filters(struct mbuf * packet)13272 necp_packet_should_skip_filters(struct mbuf *packet)
13273 {
13274 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13275 return false;
13276 }
13277
13278 // Check for overloaded value. See necp_mark_packet_from_socket().
13279 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
13280 }
13281
13282 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)13283 necp_get_last_interface_index_from_packet(struct mbuf *packet)
13284 {
13285 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13286 return 0;
13287 }
13288
13289 return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
13290 }
13291
13292 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)13293 necp_get_route_rule_id_from_packet(struct mbuf *packet)
13294 {
13295 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13296 return 0;
13297 }
13298
13299 return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
13300 }
13301
13302 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)13303 necp_get_app_uuid_from_packet(struct mbuf *packet,
13304 uuid_t app_uuid)
13305 {
13306 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13307 return EINVAL;
13308 }
13309
13310 bool found_mapping = FALSE;
13311 if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
13312 lck_rw_lock_shared(&necp_kernel_policy_lock);
13313 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);
13314 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
13315 if (entry != NULL) {
13316 uuid_copy(app_uuid, entry->uuid);
13317 found_mapping = true;
13318 }
13319 lck_rw_done(&necp_kernel_policy_lock);
13320 }
13321 if (!found_mapping) {
13322 uuid_clear(app_uuid);
13323 }
13324 return 0;
13325 }
13326
13327 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)13328 necp_get_is_keepalive_from_packet(struct mbuf *packet)
13329 {
13330 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13331 return FALSE;
13332 }
13333
13334 return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
13335 }
13336
13337 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)13338 necp_socket_get_content_filter_control_unit(struct socket *so)
13339 {
13340 struct inpcb *inp = sotoinpcb(so);
13341
13342 if (inp == NULL) {
13343 return 0;
13344 }
13345 return inp->inp_policyresult.results.filter_control_unit;
13346 }
13347
13348 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)13349 necp_socket_get_policy_gencount(struct socket *so)
13350 {
13351 struct inpcb *inp = so ? sotoinpcb(so) : NULL;
13352
13353 if (inp == NULL) {
13354 return 0;
13355 }
13356 return inp->inp_policyresult.policy_gencount;
13357 }
13358
13359 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)13360 necp_socket_should_use_flow_divert(struct inpcb *inp)
13361 {
13362 if (inp == NULL) {
13363 return FALSE;
13364 }
13365
13366 return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
13367 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13368 (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
13369 }
13370
13371 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)13372 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
13373 {
13374 if (inp == NULL) {
13375 return 0;
13376 }
13377
13378 if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13379 return 0;
13380 }
13381
13382 if (aggregate_unit != NULL &&
13383 inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13384 *aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13385 }
13386
13387 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13388 return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13389 }
13390
13391 return 0;
13392 }
13393
13394 bool
necp_socket_should_rescope(struct inpcb * inp)13395 necp_socket_should_rescope(struct inpcb *inp)
13396 {
13397 if (inp == NULL) {
13398 return FALSE;
13399 }
13400
13401 return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13402 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13403 }
13404
13405 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13406 necp_socket_get_rescope_if_index(struct inpcb *inp)
13407 {
13408 if (inp == NULL) {
13409 return 0;
13410 }
13411
13412 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13413 return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13414 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13415 return necp_get_primary_direct_interface_index();
13416 }
13417
13418 return 0;
13419 }
13420
13421 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13422 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13423 {
13424 if (inp == NULL) {
13425 return current_mtu;
13426 }
13427
13428 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13429 (inp->inp_flags & INP_BOUND_IF) &&
13430 inp->inp_boundifp) {
13431 u_int bound_interface_index = inp->inp_boundifp->if_index;
13432 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13433
13434 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13435 if (bound_interface_index != tunnel_interface_index) {
13436 ifnet_t tunnel_interface = NULL;
13437
13438 ifnet_head_lock_shared();
13439 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13440 ifnet_head_done();
13441
13442 if (tunnel_interface != NULL) {
13443 u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13444 u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13445 const char ipsec_prefix[] = "ipsec";
13446 if (delegate_tunnel_mtu != 0 &&
13447 strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13448 // For ipsec interfaces, calculate the overhead from the delegate interface
13449 u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13450 if (delegate_tunnel_mtu > tunnel_overhead) {
13451 delegate_tunnel_mtu -= tunnel_overhead;
13452 }
13453
13454 if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13455 // If the (delegate - overhead) < direct, return (delegate - overhead)
13456 return delegate_tunnel_mtu;
13457 } else {
13458 // Otherwise return direct
13459 return direct_tunnel_mtu;
13460 }
13461 } else {
13462 // For non-ipsec interfaces, just return the tunnel MTU
13463 return direct_tunnel_mtu;
13464 }
13465 }
13466 }
13467 }
13468
13469 // By default, just return the MTU passed in
13470 return current_mtu;
13471 }
13472
13473 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13474 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13475 {
13476 if (result_parameter == NULL) {
13477 return NULL;
13478 }
13479
13480 return ifindex2ifnet[result_parameter->tunnel_interface_index];
13481 }
13482
13483 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13484 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13485 {
13486 bool found_match = FALSE;
13487 bool can_rebind = FALSE;
13488 ifaddr_t ifa;
13489 union necp_sockaddr_union address_storage;
13490
13491 if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13492 return FALSE;
13493 }
13494
13495 // Match source address against interface addresses
13496 ifnet_lock_shared(interface);
13497 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13498 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13499 if (address_storage.sa.sa_family != family) {
13500 continue;
13501 }
13502
13503 if (family == AF_INET) {
13504 struct ip *ip = mtod(packet, struct ip *);
13505 if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13506 found_match = TRUE;
13507 break;
13508 }
13509 } else if (family == AF_INET6) {
13510 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13511 if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13512 found_match = TRUE;
13513 break;
13514 }
13515 }
13516 }
13517 }
13518 const uint32_t if_idx = interface->if_index;
13519 ifnet_lock_done(interface);
13520
13521 // If source address matched, attempt to construct a route to the destination address
13522 if (found_match) {
13523 ROUTE_RELEASE(new_route);
13524
13525 if (family == AF_INET) {
13526 struct ip *ip = mtod(packet, struct ip *);
13527 struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13528 dst4->sin_family = AF_INET;
13529 dst4->sin_len = sizeof(struct sockaddr_in);
13530 dst4->sin_addr = ip->ip_dst;
13531 rtalloc_scoped(new_route, if_idx);
13532 if (!ROUTE_UNUSABLE(new_route)) {
13533 can_rebind = TRUE;
13534 }
13535 } else if (family == AF_INET6) {
13536 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13537 struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13538 dst6->sin6_family = AF_INET6;
13539 dst6->sin6_len = sizeof(struct sockaddr_in6);
13540 dst6->sin6_addr = ip6->ip6_dst;
13541 rtalloc_scoped(new_route, if_idx);
13542 if (!ROUTE_UNUSABLE(new_route)) {
13543 can_rebind = TRUE;
13544 }
13545 }
13546 }
13547
13548 return can_rebind;
13549 }
13550
13551 static bool
necp_addr_is_loopback(struct sockaddr * address)13552 necp_addr_is_loopback(struct sockaddr *address)
13553 {
13554 if (address == NULL) {
13555 return FALSE;
13556 }
13557
13558 if (address->sa_family == AF_INET) {
13559 return ntohl(SIN(address)->sin_addr.s_addr) == INADDR_LOOPBACK;
13560 } else if (address->sa_family == AF_INET6) {
13561 if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13562 return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13563 } else {
13564 // Match ::ffff:127.0.0.1 loopback address
13565 in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13566 return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13567 }
13568 }
13569
13570 return FALSE;
13571 }
13572
13573 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)13574 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13575 {
13576 // Note: This function only checks for the loopback addresses.
13577 // In the future, we may want to expand to also allow any traffic
13578 // going through the loopback interface, but until then, this
13579 // check is cheaper.
13580
13581 if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13582 return TRUE;
13583 }
13584
13585 if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13586 return TRUE;
13587 }
13588
13589 if (inp != NULL) {
13590 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13591 return TRUE;
13592 }
13593 if (inp->inp_vflag & INP_IPV4) {
13594 if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
13595 ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
13596 return TRUE;
13597 }
13598 } else if (inp->inp_vflag & INP_IPV6) {
13599 if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13600 IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13601 return TRUE;
13602 }
13603 }
13604 } else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13605 return TRUE;
13606 }
13607
13608 if (packet != NULL) {
13609 struct ip *ip = mtod(packet, struct ip *);
13610 if (ip->ip_v == 4) {
13611 if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
13612 return TRUE;
13613 }
13614 if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
13615 return TRUE;
13616 }
13617 } else if (ip->ip_v == 6) {
13618 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13619 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13620 return TRUE;
13621 }
13622 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13623 return TRUE;
13624 }
13625 }
13626 }
13627
13628 return FALSE;
13629 }
13630
13631 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13632 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13633 {
13634 if (inp != NULL) {
13635 if (!(inp->inp_vflag & INP_IPV6)) {
13636 return false;
13637 }
13638 if (INP_INTCOPROC_ALLOWED(inp)) {
13639 return true;
13640 }
13641 if ((inp->inp_flags & INP_BOUND_IF) &&
13642 IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13643 return true;
13644 }
13645 return false;
13646 }
13647 if (packet != NULL) {
13648 struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13649 struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13650 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13651 NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13652 return true;
13653 }
13654 }
13655
13656 return false;
13657 }
13658
13659 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13660 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13661 {
13662 char dest_str[MAX_IPv6_STR_LEN];
13663
13664 if (necp_drop_dest_debug > 0) {
13665 if (sau->sa.sa_family == AF_INET) {
13666 (void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13667 } else if (sau->sa.sa_family == AF_INET6) {
13668 (void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13669 } else {
13670 dest_str[0] = 0;
13671 }
13672 }
13673 for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13674 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13675 struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13676
13677 if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13678 if (necp_drop_dest_debug > 0) {
13679 char subnet_str[MAX_IPv6_STR_LEN];
13680 struct proc *p = current_proc();
13681 pid_t pid = proc_pid(p);
13682
13683 if (sau->sa.sa_family == AF_INET) {
13684 (void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13685 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);
13686 } else if (sau->sa.sa_family == AF_INET6) {
13687 (void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13688 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);
13689 }
13690 }
13691 return true;
13692 }
13693 }
13694 if (necp_drop_dest_debug > 1) {
13695 struct proc *p = current_proc();
13696 pid_t pid = proc_pid(p);
13697
13698 os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13699 }
13700 return false;
13701 }
13702
13703 static int
13704 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13705 {
13706 #pragma unused(arg1, arg2, oidp)
13707 int changed = 0;
13708 int error = 0;
13709 struct necp_drop_dest_policy tmp_drop_dest_policy;
13710 struct proc *p = current_proc();
13711 pid_t pid = proc_pid(p);
13712
13713 if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13714 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13715 NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13716 return EPERM;
13717 }
13718 if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13719 NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13720 return EINVAL;
13721 }
13722
13723 memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13724 error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13725 if (error != 0) {
13726 NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13727 return error;
13728 }
13729 if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13730 return error;
13731 }
13732
13733 //
13734 // Validate the passed parameters
13735 //
13736 if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13737 NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13738 return EINVAL;
13739 }
13740 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13741 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13742 struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13743
13744 switch (tmp_drop_dest_entry->level) {
13745 case NECP_SESSION_PRIORITY_UNKNOWN:
13746 if (tmp_drop_dest_policy.entry_count != 0) {
13747 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);
13748 return EINVAL;
13749 }
13750 break;
13751 case NECP_SESSION_PRIORITY_CONTROL:
13752 case NECP_SESSION_PRIORITY_CONTROL_1:
13753 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13754 case NECP_SESSION_PRIORITY_HIGH:
13755 case NECP_SESSION_PRIORITY_HIGH_1:
13756 case NECP_SESSION_PRIORITY_HIGH_2:
13757 case NECP_SESSION_PRIORITY_HIGH_3:
13758 case NECP_SESSION_PRIORITY_HIGH_4:
13759 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13760 case NECP_SESSION_PRIORITY_DEFAULT:
13761 case NECP_SESSION_PRIORITY_LOW:
13762 if (tmp_drop_dest_policy.entry_count == 0) {
13763 NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13764 return EINVAL;
13765 }
13766 break;
13767 default: {
13768 NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13769 return EINVAL;
13770 }
13771 }
13772
13773 switch (npca->address.sa.sa_family) {
13774 case AF_INET: {
13775 if (npca->prefix > 32) {
13776 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13777 return EINVAL;
13778 }
13779 if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
13780 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
13781 return EINVAL;
13782 }
13783 if (npca->address.sin.sin_port != 0) {
13784 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);
13785 return EINVAL;
13786 }
13787 break;
13788 }
13789 case AF_INET6: {
13790 if (npca->prefix > 128) {
13791 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13792 return EINVAL;
13793 }
13794 if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
13795 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
13796 return EINVAL;
13797 }
13798 if (npca->address.sin6.sin6_port != 0) {
13799 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);
13800 return EINVAL;
13801 }
13802 if (npca->address.sin6.sin6_flowinfo != 0) {
13803 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);
13804 return EINVAL;
13805 }
13806 if (npca->address.sin6.sin6_scope_id != 0) {
13807 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);
13808 return EINVAL;
13809 }
13810 break;
13811 }
13812 default: {
13813 return EINVAL;
13814 }
13815 }
13816 }
13817
13818 //
13819 // Commit the changed policy
13820 //
13821 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
13822 memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
13823
13824 necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
13825 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13826 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13827 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13828
13829 memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
13830
13831 necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
13832 }
13833 lck_rw_done(&necp_kernel_policy_lock);
13834
13835 return 0;
13836 }
13837
13838 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])13839 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
13840 {
13841 uint16_t fam = address->sa.sa_family;
13842 memset(addr_str, 0, MAX_IPv6_STR_LEN);
13843 if (fam == AF_INET) {
13844 (void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
13845 } else if (fam == AF_INET6) {
13846 (void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
13847 }
13848 return __unsafe_null_terminated_from_indexable(addr_str);
13849 }
13850