1 /*
2 * Copyright (c) 2013-2023 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
80 #include <net/sockaddr_utils.h>
81
82 /*
83 * NECP - Network Extension Control Policy database
84 * ------------------------------------------------
85 * The goal of this module is to allow clients connecting via a
86 * policy file descriptor to create high-level policy sessions, which
87 * are ingested into low-level kernel policies that control and tag
88 * traffic at the application, socket, and IP layers.
89 *
90 * ------------------------------------------------
91 * Sessions
92 * ------------------------------------------------
93 * Each session owns a list of session policies, each of which can
94 * specify any combination of conditions and a single result. Each
95 * session also has a priority level (such as High, Default, or Low)
96 * which is requested by the client. Based on the requested level,
97 * a session order value is assigned to the session, which will be used
98 * to sort kernel policies generated by the session. The session client
99 * can specify the sub-order for each policy it creates which will be
100 * used to further sort the kernel policies.
101 *
102 * Policy fd --> 1 necp_session --> list of necp_session_policy structs
103 *
104 * ------------------------------------------------
105 * Kernel Policies
106 * ------------------------------------------------
107 * Whenever a session send the Apply command, its policies are ingested
108 * and generate kernel policies. There are two phases of kernel policy
109 * ingestion.
110 *
111 * 1. The session policy is parsed to create kernel policies at the socket
112 * and IP layers, when applicable. For example, a policy that requires
113 * all traffic from App1 to Pass will generate a socket kernel policy to
114 * match App1 and mark packets with ID1, and also an IP policy to match
115 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
116 * resulting kernel policies are added to the global socket and IP layer
117 * policy lists.
118 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
119 * || ||
120 * \/ \/
121 * necp_kernel_socket_policies necp_kernel_ip_output_policies
122 *
123 * 2. Once the global lists of kernel policies have been filled out, each
124 * list is traversed to create optimized sub-lists ("Maps") which are used during
125 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
126 * which hashes incoming packets based on marked socket-layer policies, and removes
127 * duplicate or overlapping policies. Socket policies are sent into two maps,
128 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
129 * The app layer map is used for policy checks coming in from user space, and is one
130 * list with duplicate and overlapping policies removed. The socket map hashes based
131 * on app UUID, and removes duplicate and overlapping policies.
132 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
133 * |-> necp_kernel_socket_policies_map
134 *
135 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
136 *
137 * ------------------------------------------------
138 * Drop All Level
139 * ------------------------------------------------
140 * The Drop All Level is a sysctl that controls the level at which policies are allowed
141 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
142 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
143 * by a session with a priority level better than (numerically less than) the
144 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
145 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
146 * session orders to be dropped.
147 */
148
149 u_int32_t necp_drop_all_order = 0;
150 u_int32_t necp_drop_all_level = 0;
151
152 u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
153 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
154 u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
155 u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
156 u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
157
158 u_int32_t necp_drop_unentitled_order = 0;
159 #ifdef XNU_TARGET_OS_WATCH
160 u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
161 #else // XNU_TARGET_OS_WATCH
162 u_int32_t necp_drop_unentitled_level = 0;
163 #endif // XNU_TARGET_OS_WATCH
164
165 u_int32_t necp_drop_management_order = 0;
166 u_int32_t necp_drop_management_level = NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL;
167
168 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
169
170 os_log_t necp_log_handle = NULL;
171 os_log_t necp_data_trace_log_handle = NULL;
172
173 u_int32_t necp_session_count = 0;
174
175 static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
176 struct necp_session_policy, NET_KT_DEFAULT);
177 static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
178 struct necp_kernel_socket_policy, NET_KT_DEFAULT);
179 static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
180 struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
181
182 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
183 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
184 LIST_INSERT_HEAD((head), elm, field); \
185 } else { \
186 LIST_FOREACH(tmpelm, head, field) { \
187 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
188 LIST_INSERT_AFTER(tmpelm, elm, field); \
189 break; \
190 } \
191 } \
192 } \
193 } while (0)
194
195 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
196 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
197 LIST_INSERT_HEAD((head), elm, field); \
198 } else { \
199 LIST_FOREACH(tmpelm, head, field) { \
200 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))) { \
201 LIST_INSERT_AFTER(tmpelm, elm, field); \
202 break; \
203 } \
204 } \
205 } \
206 } while (0)
207
208 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
209 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))) { \
210 LIST_INSERT_HEAD((head), elm, field); \
211 } else { \
212 LIST_FOREACH(tmpelm, head, field) { \
213 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))) { \
214 LIST_INSERT_AFTER(tmpelm, elm, field); \
215 break; \
216 } \
217 } \
218 } \
219 } while (0)
220
221 #define IS_NECP_ROUTE_RULE_DENY(x) ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE)
222
223 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x) (IS_NECP_ROUTE_RULE_DENY(x) || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
224
225 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x000001
226 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x000002
227 #define NECP_KERNEL_CONDITION_PROTOCOL 0x000004
228 #define NECP_KERNEL_CONDITION_LOCAL_START 0x000008
229 #define NECP_KERNEL_CONDITION_LOCAL_END 0x000010
230 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x000020
231 #define NECP_KERNEL_CONDITION_REMOTE_START 0x000040
232 #define NECP_KERNEL_CONDITION_REMOTE_END 0x000080
233 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x000100
234 #define NECP_KERNEL_CONDITION_APP_ID 0x000200
235 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x000400
236 #define NECP_KERNEL_CONDITION_DOMAIN 0x000800
237 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x001000
238 #define NECP_KERNEL_CONDITION_POLICY_ID 0x002000
239 #define NECP_KERNEL_CONDITION_PID 0x004000
240 #define NECP_KERNEL_CONDITION_UID 0x008000
241 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x010000 // Only set from packets looping between interfaces
242 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x020000
243 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x040000
244 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 0x080000
245 #define NECP_KERNEL_CONDITION_AGENT_TYPE 0x100000
246 #define NECP_KERNEL_CONDITION_HAS_CLIENT 0x200000
247 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS 0x400000
248 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS 0x800000
249 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY 0x1000000
250 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY 0x2000000
251 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY 0x4000000
252 #define NECP_KERNEL_CONDITION_SDK_VERSION 0x8000000
253 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x10000000
254 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 0x20000000
255 #define NECP_KERNEL_CONDITION_IS_LOOPBACK 0x40000000
256 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY 0x80000000
257 #define NECP_KERNEL_CONDITION_SCHEME_PORT 0x100000000
258 #define NECP_KERNEL_CONDITION_DOMAIN_FILTER 0x200000000
259 #define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT 0x400000000
260 #define NECP_KERNEL_CONDITION_EXACT_DOMAIN 0x800000000
261 #define NECP_KERNEL_CONDITION_REAL_UID 0x1000000000
262 #define NECP_KERNEL_CONDITION_URL 0x2000000000
263 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS 0x4000000000
264
265 #define NECP_MAX_POLICY_RESULT_SIZE 512
266 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
267 #define NECP_MAX_CONDITIONS_ARRAY_SIZE 4096
268 #define NECP_MAX_POLICY_LIST_COUNT 1024
269
270 #define NECP_MAX_DOMAIN_FILTER_SIZE 65536 // Allows room for 100K domains
271
272 typedef enum {
273 NECP_BYPASS_TYPE_NONE = 0,
274 NECP_BYPASS_TYPE_INTCOPROC = 1,
275 NECP_BYPASS_TYPE_LOOPBACK = 2,
276 NECP_BYPASS_TYPE_DROP = 3, // Drop now without hitting necp policies
277 } necp_socket_bypass_type_t;
278
279 // Cap the policy size at the max result + conditions size, with room for extra TLVs
280 #define NECP_MAX_POLICY_SIZE (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
281
282 struct necp_service_registration {
283 LIST_ENTRY(necp_service_registration) session_chain;
284 LIST_ENTRY(necp_service_registration) kernel_chain;
285 u_int32_t service_id;
286 };
287
288 struct necp_domain_filter {
289 LIST_ENTRY(necp_domain_filter) owner_chain;
290 LIST_ENTRY(necp_domain_filter) chain;
291 u_int32_t id;
292 struct net_bloom_filter *filter;
293 os_refcnt_t refcount;
294 };
295 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
296
297 struct necp_session {
298 u_int8_t necp_fd_type;
299 u_int32_t control_unit;
300 u_int32_t session_priority; // Descriptive priority rating
301 u_int32_t session_order;
302
303 necp_policy_id last_policy_id;
304
305 decl_lck_mtx_data(, lock);
306
307 bool proc_locked; // Messages must come from proc_uuid
308 uuid_t proc_uuid;
309 int proc_pid;
310
311 bool dirty;
312 LIST_HEAD(_policies, necp_session_policy) policies;
313
314 LIST_HEAD(_services, necp_service_registration) services;
315 struct necp_domain_filter_list domain_filters;
316
317 TAILQ_ENTRY(necp_session) chain;
318 };
319
320 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
321 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
322
323 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
324
325 struct necp_socket_info {
326 pid_t pid;
327 int32_t pid_version;
328 uid_t uid;
329 uid_t real_uid;
330 union necp_sockaddr_union local_addr;
331 union necp_sockaddr_union remote_addr;
332 u_int32_t bound_interface_index;
333 u_int32_t bound_interface_flags;
334 u_int32_t bound_interface_eflags;
335 u_int32_t bound_interface_xflags;
336 u_int32_t traffic_class;
337 u_int16_t protocol;
338 u_int16_t scheme_port;
339 u_int32_t application_id;
340 u_int32_t real_application_id;
341 u_int32_t account_id;
342 u_int32_t drop_order;
343 u_int32_t client_flags;
344 char *domain __null_terminated;
345 char *url __null_terminated;
346 unsigned is_entitled : 1;
347 unsigned has_client : 1;
348 unsigned has_system_signed_result : 1;
349 unsigned is_platform_binary : 1;
350 unsigned used_responsible_pid : 1;
351 unsigned is_loopback : 1;
352 unsigned real_is_platform_binary : 1;
353 unsigned is_delegated : 1;
354 unsigned is_local : 1;
355 unsigned __pad_bits : 7;
356 };
357
358 static LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
359 static LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
360 static LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
361 &necp_kernel_policy_mtx_attr);
362
363 static LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
364 static LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
365
366 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
367
368 /*
369 * On modification, invalidate cached lookups by bumping the generation count.
370 * Other calls will need to take the slowpath of taking
371 * the subsystem lock.
372 */
373 static volatile int32_t necp_kernel_socket_policies_gencount;
374 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
375 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
376 necp_kernel_socket_policies_gencount = 1; \
377 } \
378 } while (0)
379
380 /*
381 * Drop-all Bypass:
382 * Allow priviledged processes to bypass the default drop-all
383 * via entitlement check. For OSX, since entitlement check is
384 * not supported for configd, configd signing identity is checked
385 * instead.
386 */
387 #define SIGNING_ID_CONFIGD "com.apple.configd"
388 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
389
390 typedef enum {
391 NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
392 NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
393 NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
394 } necp_drop_all_bypass_check_result_t;
395
396 static u_int64_t necp_kernel_application_policies_condition_mask;
397 static size_t necp_kernel_application_policies_count;
398 static u_int64_t necp_kernel_socket_policies_condition_mask;
399 static size_t necp_kernel_socket_policies_count;
400 static size_t necp_kernel_socket_policies_non_app_count;
401 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
402 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
403 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
404 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
405 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
406 static size_t necp_kernel_socket_policies_app_layer_map_count;
407 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_app_layer_map;
408 /*
409 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
410 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
411 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
412 *
413 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
414 */
415
416 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
417 static size_t necp_kernel_ip_output_policies_count;
418 static size_t necp_kernel_ip_output_policies_non_id_count;
419 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
420 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
421 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
422 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
423 static struct necp_kernel_ip_output_policy ** __indexable necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
424 static struct necp_kernel_socket_policy pass_policy =
425 {
426 .id = NECP_KERNEL_POLICY_ID_NO_MATCH,
427 .result = NECP_KERNEL_POLICY_RESULT_PASS,
428 };
429
430 static struct necp_session *necp_create_session(void);
431 static void necp_delete_session(struct necp_session *session);
432
433 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
434 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
435 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
436
437 #define MAX_RESULT_STRING_LEN 64
438 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);
439
440 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);
441 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
442 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
443 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
444 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
445 static void necp_policy_apply_all(struct necp_session *session);
446
447 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);
448 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
449 static bool necp_kernel_socket_policies_reprocess(void);
450 static bool necp_kernel_socket_policies_update_uuid_table(void);
451 static inline struct necp_kernel_socket_policy * necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
452 struct necp_socket_info *info,
453 necp_kernel_policy_filter *return_filter,
454 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
455 size_t *return_route_rule_id_array_count,
456 size_t route_rule_id_array_count,
457 necp_kernel_policy_result *return_service_action,
458 necp_kernel_policy_service *return_service,
459 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
460 size_t netagent_array_count,
461 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
462 size_t netagent_use_flags_array_count,
463 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
464 u_int32_t num_required_agent_types,
465 proc_t proc,
466 u_int16_t pf_tag,
467 necp_kernel_policy_id *skip_policy_id,
468 struct rtentry *rt,
469 necp_kernel_policy_result *return_drop_dest_policy_result,
470 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
471 u_int32_t *return_flow_divert_aggregate_unit,
472 struct socket *so,
473 int debug);
474 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);
475 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
476 static bool necp_kernel_ip_output_policies_reprocess(void);
477
478 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
479 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);
480 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
481 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
482 static bool necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits);
483 static bool necp_addr_is_empty(struct sockaddr *addr);
484 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);
485 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
486
487 struct necp_uuid_id_mapping {
488 LIST_ENTRY(necp_uuid_id_mapping) chain;
489 uuid_t uuid;
490 u_int32_t id;
491 os_refcnt_t refcount;
492 u_int32_t table_usecount; // Add to UUID policy table count
493 };
494 static size_t necp_num_uuid_app_id_mappings;
495 static bool necp_uuid_app_id_mappings_dirty;
496 #define NECP_UUID_APP_ID_HASH_SIZE 64
497 static u_long necp_uuid_app_id_hash_mask;
498 static u_long necp_uuid_app_id_hash_num_buckets;
499 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
500 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
501 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
502 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
503 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
504
505 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
506 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
507 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
508 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
509 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
510
511 struct necp_string_id_mapping {
512 LIST_ENTRY(necp_string_id_mapping) chain;
513 char *string __null_terminated;
514 necp_app_id id;
515 os_refcnt_t refcount;
516 };
517 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
518 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
519 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
520 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
521
522 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);
523 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
524 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
525
526 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
527 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
528
529 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
530
531 static char * __null_terminated necp_create_trimmed_domain(char * __sized_by(length)string, size_t length);
532 static inline int necp_count_dots(char * __sized_by(length)string, size_t length);
533
534 static char * __null_terminated necp_copy_string(char * __sized_by(length)string, size_t length);
535 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);
536
537 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
538
539 #define MAX_ROUTE_RULE_INTERFACES 10
540 struct necp_route_rule {
541 LIST_ENTRY(necp_route_rule) chain;
542 u_int32_t id;
543 u_int32_t netagent_id;
544 u_int32_t control_unit;
545 u_int32_t match_netagent_id;
546 u_int32_t effective_type;
547 u_int8_t default_action;
548 u_int8_t cellular_action;
549 u_int8_t wifi_action;
550 u_int8_t wired_action;
551 u_int8_t expensive_action;
552 u_int8_t constrained_action;
553 u_int8_t companion_action;
554 u_int8_t vpn_action;
555 u_int exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
556 u_int8_t exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
557 os_refcnt_t refcount;
558 };
559 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
560 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);
561 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
562 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
563 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,
564 u_int32_t route_rule_id, u_int32_t *interface_type_denied);
565 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);
566 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
567 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);
568 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
569 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
570
571 #define MAX_AGGREGATE_ROUTE_RULES 16
572 struct necp_aggregate_route_rule {
573 LIST_ENTRY(necp_aggregate_route_rule) chain;
574 u_int32_t id;
575 u_int32_t rule_ids[MAX_AGGREGATE_ROUTE_RULES];
576 };
577 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
578 static u_int32_t necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids);
579
580 // Sysctl definitions
581 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
582 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
583 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
584
585 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
586 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
587 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
588 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
589 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
590 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
591 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
592 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", "");
593 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", "");
594 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", "");
595 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
596 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, "");
597 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
598 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
599
600 static struct necp_drop_dest_policy necp_drop_dest_policy;
601 static int necp_drop_dest_debug = 0; // 0: off, 1: match, >1: every evaluation
602 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
603
604 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
605 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
606 0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
607
608 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
609
610 /*
611 * data tracing control -
612 *
613 * necp_data_tracing_level : 1 for brief trace, 2 for policy details, 3 for condition details
614 * necp_data_tracing_port : match traffic with specified port
615 * necp_data_tracing_proto : match traffic with specified protocol
616 * necp_data_tracing_pid : match traffic with specified pid (only applied at socket level)
617 * necp_data_tracing_ifindex : match traffic on specified ifindex
618 * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched. Default is 0 to trace traffic if any specified attributes matched.
619 * data_tracing_session_order : match policies in the specified session - log traffic that hit these policies
620 * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
621 */
622 static int necp_data_tracing_level = 0;
623 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
624
625 static int necp_data_tracing_port = 0;
626 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
627
628 static int necp_data_tracing_proto = 0;
629 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
630
631 static int necp_data_tracing_pid = 0;
632 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
633
634 static int necp_data_tracing_ifindex = 0;
635 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
636
637 static int necp_data_tracing_match_all = 0;
638 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
639
640 static int necp_data_tracing_session_order = 0;
641 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
642
643 static int necp_data_tracing_policy_order = 0;
644 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
645
646 #define NECP_DATA_TRACE_LEVEL_BRIEF 1
647 #define NECP_DATA_TRACE_LEVEL_POLICY 2
648 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
649 #define NECP_DATA_TRACE_LEVEL_DP 4
650
651 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
652 (pid == necp_data_tracing_pid)
653 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
654 (protocol == necp_data_tracing_proto)
655 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
656 (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
657 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
658 (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
659 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
660 (ifindex == necp_data_tracing_ifindex)
661
662 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
663 ((necp_data_tracing_level && \
664 ((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
665 (necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
666 (necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
667 (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)
668
669 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
670 ((necp_data_tracing_level && \
671 ((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
672 (!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
673 (!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
674 (!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)
675
676 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
677 (necp_data_tracing_match_all ? \
678 NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
679 NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
680
681 #define NECP_DATA_TRACE_ON(debug) (debug)
682 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
683 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
684 #define NECP_DATA_TRACE_DP_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_CONDITION)
685
686 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
687
688 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
689 if (NECP_DATA_TRACE_ON(debug)) { \
690 char laddr_str[MAX_IPv6_STR_LEN]; \
691 char raddr_str[MAX_IPv6_STR_LEN]; \
692 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>", \
693 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); \
694 }
695
696 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
697 if (NECP_DATA_TRACE_ON(debug)) { \
698 char laddr_str[MAX_IPv6_STR_LEN]; \
699 char raddr_str[MAX_IPv6_STR_LEN]; \
700 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>", \
701 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); \
702 }
703
704 #define NECP_DATA_TRACE_LOG_SOCKET_DP(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
705 if (NECP_DATA_TRACE_ON(debug)) { \
706 char laddr_str[MAX_IPv6_STR_LEN]; \
707 char raddr_str[MAX_IPv6_STR_LEN]; \
708 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>", \
709 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); \
710 }
711
712 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
713 if (NECP_DATA_TRACE_ON(debug)) { \
714 char laddr_str[MAX_IPv6_STR_LEN]; \
715 char raddr_str[MAX_IPv6_STR_LEN]; \
716 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)", \
717 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]); \
718 }
719
720 #define NECP_DATA_TRACE_LOG_SOCKET_BRIEF(debug, socket, caller, log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id) \
721 if (NECP_DATA_TRACE_ON(debug)) { \
722 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - <policy_id %d skip_policy_id %d> <cached policy_id %d skip_policy_id %d>", \
723 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id); \
724 }
725
726 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
727 if (NECP_DATA_TRACE_ON(debug)) { \
728 char laddr_str[MAX_IPv6_STR_LEN]; \
729 char raddr_str[MAX_IPv6_STR_LEN]; \
730 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>", \
731 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)); \
732 }
733
734 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
735 if (NECP_DATA_TRACE_ON(debug)) { \
736 char laddr_str[MAX_IPv6_STR_LEN]; \
737 char raddr_str[MAX_IPv6_STR_LEN]; \
738 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>", \
739 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); \
740 }
741
742 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
743 if (NECP_DATA_TRACE_ON(debug)) { \
744 char laddr_str[MAX_IPv6_STR_LEN]; \
745 char raddr_str[MAX_IPv6_STR_LEN]; \
746 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)", \
747 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]); \
748 }
749
750 #define NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, socket, caller, log_msg) \
751 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
752 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)", \
753 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); \
754 }
755
756 #define NECP_DATA_TRACE_LOG_POLICY_IP(debug, caller, log_msg) \
757 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
758 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)", \
759 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); \
760 }
761
762 #define NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
763 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
764 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)>", \
765 caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
766 }
767
768 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
769 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
770 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
771 caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
772 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
773 }
774
775 #define NECP_DATA_TRACE_LOG_CONDITION_IP(debug, caller, negate, name, val, input) \
776 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
777
778 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR(debug, caller, negate, name, val, input) \
779 NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
780
781
782 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
783 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
784 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)>", \
785 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
786 }
787
788 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
789 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
790 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
791 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
792 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
793 }
794
795 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, caller, negate, name, val, input) \
796 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val, 0, 0, input, 0, 0)
797
798 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, caller, negate, name, val, input) \
799 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
800
801 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
802 (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
803 addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
804
805 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
806 "INVALID",
807 "PASS",
808 "SKIP",
809 "DROP",
810 "SOCKET_DIVERT",
811 "SOCKET_FILTER",
812 "IP_TUNNEL",
813 "IP_FILTER",
814 "TRIGGER",
815 "TRIGGER_IF_NEEDED",
816 "TRIGGER_SCOPED",
817 "NO_TRIGGER_SCOPED",
818 "SOCKET_SCOPED",
819 "ROUTE_RULES",
820 "USE_NETAGENT",
821 "NETAGENT_SCOPED",
822 "SCOPED_DIRECT",
823 "ALLOW_UNENTITLED",
824 "REMOVE_NETAGENT"
825 };
826
827
828 #define NECP_DDE_ENTITLEMENT "com.apple.developer.media-device-discovery-extension"
829
830 static int necp_drop_loopback_count = 0;
831 SYSCTL_INT(_net_necp, OID_AUTO, drop_loopback_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_drop_loopback_count, 0, "");
832
833 static bool
necp_address_is_local_interface_address(union necp_sockaddr_union * addr)834 necp_address_is_local_interface_address(union necp_sockaddr_union *addr)
835 {
836 bool is_interface_address = false;
837 if (addr == NULL) {
838 return false;
839 }
840
841 // Clean up the address before comparison with interface addresses
842 // Transform remote_addr into the ifaddr form
843 // IPv6 Scope IDs are always embedded in the ifaddr list
844 struct sockaddr_storage remote_address_sanitized;
845 u_int ifscope = IFSCOPE_NONE;
846 (void)sa_copy(SA(addr), &remote_address_sanitized, &ifscope);
847 SIN(&remote_address_sanitized)->sin_port = 0;
848 if (remote_address_sanitized.ss_family == AF_INET6) {
849 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
850 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
851 }
852 }
853
854 // Check if remote address is an interface address
855 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
856 if (ifa != NULL && ifa->ifa_ifp != NULL) {
857 is_interface_address = true;
858 }
859 if (ifa != NULL) {
860 ifaddr_release(ifa);
861 ifa = NULL;
862 }
863
864 return is_interface_address;
865 }
866
867 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, addr, include_local_addresses) \
868 ((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)))
869
870 // Session order allocation
871 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)872 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
873 {
874 u_int32_t new_order = 0;
875
876 // For now, just allocate 1000 orders for each priority
877 if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
878 priority = NECP_SESSION_PRIORITY_DEFAULT;
879 }
880
881 // Use the control unit to decide the offset into the priority list
882 new_order = (control_unit) + ((priority - 1) * 1000);
883
884 return new_order;
885 }
886
887 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)888 necp_get_first_order_for_priority(u_int32_t priority)
889 {
890 if (priority == 0) {
891 return 0;
892 }
893 return ((priority - 1) * 1000) + 1;
894 }
895
896 // Sysctl handler
897 static int
898 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
899 {
900 #pragma unused(arg1, arg2)
901 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
902 necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
903 return error;
904 }
905
906 static int
907 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
908 {
909 #pragma unused(arg1, arg2)
910 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
911 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
912 return error;
913 }
914
915 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
916 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)917 _necp_process_drop_order_inner(kauth_cred_t cred)
918 {
919 if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
920 priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
921 return necp_drop_unentitled_order;
922 } else {
923 return 0;
924 }
925 }
926
927 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
928 #pragma GCC poison _necp_process_drop_order_inner
929
930 static int
931 sysctl_handle_necp_management_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_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
936 return error;
937 }
938
939 // Session fd
940
941 static int necp_session_op_close(struct fileglob *, vfs_context_t);
942
943 static const struct fileops necp_session_fd_ops = {
944 .fo_type = DTYPE_NETPOLICY,
945 .fo_read = fo_no_read,
946 .fo_write = fo_no_write,
947 .fo_ioctl = fo_no_ioctl,
948 .fo_select = fo_no_select,
949 .fo_close = necp_session_op_close,
950 .fo_drain = fo_no_drain,
951 .fo_kqfilter = fo_no_kqfilter,
952 };
953
954 static inline int
necp_is_platform_binary(proc_t proc)955 necp_is_platform_binary(proc_t proc)
956 {
957 return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
958 }
959
960 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)961 necp_check_drop_all_bypass_result(proc_t proc)
962 {
963 if (proc == NULL) {
964 proc = current_proc();
965 if (proc == NULL) {
966 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
967 }
968 }
969
970 #if defined(XNU_TARGET_OS_OSX)
971 const char *signing_id __null_terminated = NULL;
972 const bool isConfigd = (necp_is_platform_binary(proc) &&
973 (signing_id = cs_identity_get(proc)) &&
974 (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
975 (strcmp(signing_id, SIGNING_ID_CONFIGD) == 0));
976 if (isConfigd) {
977 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
978 }
979 #endif
980
981 const task_t __single task = proc_task(proc);
982 if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
983 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
984 } else {
985 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
986 }
987 }
988
989 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)990 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
991 {
992 #pragma unused(uap)
993 int error = 0;
994 struct necp_session *session = NULL;
995 struct fileproc * __single fp = NULL;
996 int fd = -1;
997 uid_t uid = kauth_cred_getuid(kauth_cred_get());
998
999 if (!necp_is_platform_binary(p)) {
1000 NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
1001 error = EACCES;
1002 goto done;
1003 }
1004
1005 if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
1006 NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
1007 error = EACCES;
1008 goto done;
1009 }
1010
1011 error = falloc(p, &fp, &fd);
1012 if (error != 0) {
1013 goto done;
1014 }
1015
1016 session = necp_create_session();
1017 if (session == NULL) {
1018 error = ENOMEM;
1019 goto done;
1020 }
1021
1022 fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
1023 fp->fp_glob->fg_flag = 0;
1024 fp->fp_glob->fg_ops = &necp_session_fd_ops;
1025 fp_set_data(fp, session);
1026
1027 proc_fdlock(p);
1028 procfdtbl_releasefd(p, fd, NULL);
1029 fp_drop(p, fd, fp, 1);
1030 proc_fdunlock(p);
1031
1032 *retval = fd;
1033 done:
1034 if (error != 0) {
1035 if (fp != NULL) {
1036 fp_free(p, fd, fp);
1037 fp = NULL;
1038 }
1039 }
1040
1041 return error;
1042 }
1043
1044 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)1045 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
1046 {
1047 #pragma unused(ctx)
1048 struct necp_session *session = (struct necp_session *)fg_get_data(fg);
1049 fg_set_data(fg, NULL);
1050
1051 if (session != NULL) {
1052 necp_policy_mark_all_for_deletion(session);
1053 necp_policy_apply_all(session);
1054 necp_delete_session(session);
1055 return 0;
1056 } else {
1057 return ENOENT;
1058 }
1059 }
1060
1061 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)1062 necp_session_find_from_fd(struct proc *p, int fd,
1063 struct fileproc **fpp, struct necp_session **session)
1064 {
1065 struct fileproc * __single fp = NULL;
1066 int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
1067
1068 if (error == 0) {
1069 *fpp = fp;
1070 *session = (struct necp_session *)fp_get_data(fp);
1071 if ((*session)->necp_fd_type != necp_fd_type_session) {
1072 // Not a client fd, ignore
1073 fp_drop(p, fd, fp, 0);
1074 error = EINVAL;
1075 }
1076 }
1077
1078 return error;
1079 }
1080
1081 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1082 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1083 {
1084 int error = 0;
1085 u_int8_t * __indexable tlv_buffer = NULL;
1086
1087 if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
1088 NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1089 error = EINVAL;
1090 goto done;
1091 }
1092
1093 if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
1094 NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1095 error = EINVAL;
1096 goto done;
1097 }
1098
1099 if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
1100 error = ENOMEM;
1101 goto done;
1102 }
1103
1104 error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
1105 if (error != 0) {
1106 NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1107 goto done;
1108 }
1109
1110 necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1111 if (error != 0) {
1112 NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1113 goto done;
1114 }
1115
1116 error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1117 if (error != 0) {
1118 NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1119 goto done;
1120 }
1121
1122 done:
1123 if (tlv_buffer != NULL) {
1124 kfree_data(tlv_buffer, uap->in_buffer_length);
1125 tlv_buffer = NULL;
1126 }
1127 *retval = error;
1128
1129 return error;
1130 }
1131
1132 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1133 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1134 {
1135 int error = 0;
1136 u_int8_t * __indexable response = NULL;
1137
1138 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1139 NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1140 error = EINVAL;
1141 goto done;
1142 }
1143
1144 necp_policy_id policy_id = 0;
1145 error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1146 if (error != 0) {
1147 NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1148 goto done;
1149 }
1150
1151 struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1152 if (policy == NULL || policy->pending_deletion) {
1153 NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1154 error = ENOENT;
1155 goto done;
1156 }
1157
1158 u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1159 u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1160 u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1161
1162 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1163 NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1164 error = EINVAL;
1165 goto done;
1166 }
1167
1168 if (response_size > NECP_MAX_POLICY_SIZE) {
1169 NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1170 error = EINVAL;
1171 goto done;
1172 }
1173
1174 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1175 if (response == NULL) {
1176 error = ENOMEM;
1177 goto done;
1178 }
1179
1180 u_int8_t *cursor = response;
1181 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1182 if (result_tlv_size) {
1183 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, (void *)&policy->result, response, response_size);
1184 }
1185 if (policy->conditions_size) {
1186 memcpy(response + (cursor - response), policy->conditions, policy->conditions_size);
1187 }
1188
1189 error = copyout(response, uap->out_buffer, response_size);
1190 if (error != 0) {
1191 NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1192 goto done;
1193 }
1194
1195 done:
1196 if (response != NULL) {
1197 kfree_data(response, response_size);
1198 response = NULL;
1199 }
1200 *retval = error;
1201
1202 return error;
1203 }
1204
1205 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1206 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1207 {
1208 int error = 0;
1209
1210 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1211 NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1212 error = EINVAL;
1213 goto done;
1214 }
1215
1216 necp_policy_id delete_policy_id = 0;
1217 error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1218 if (error != 0) {
1219 NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1220 goto done;
1221 }
1222
1223 struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1224 if (policy == NULL || policy->pending_deletion) {
1225 NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1226 error = ENOENT;
1227 goto done;
1228 }
1229
1230 necp_policy_mark_for_deletion(session, policy);
1231 done:
1232 *retval = error;
1233 return error;
1234 }
1235
1236 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1237 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1238 {
1239 #pragma unused(uap)
1240 necp_policy_apply_all(session);
1241 *retval = 0;
1242 return 0;
1243 }
1244
1245 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1246 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1247 {
1248 u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1249 u_int32_t response_size = 0;
1250 u_int8_t * __indexable response = NULL;
1251 int num_policies = 0;
1252 int cur_policy_index = 0;
1253 int error = 0;
1254 struct necp_session_policy *policy;
1255
1256 LIST_FOREACH(policy, &session->policies, chain) {
1257 if (!policy->pending_deletion) {
1258 num_policies++;
1259 }
1260 }
1261
1262 if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1263 NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1264 error = EINVAL;
1265 goto done;
1266 }
1267
1268 response_size = num_policies * tlv_size;
1269 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1270 NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1271 error = EINVAL;
1272 goto done;
1273 }
1274
1275 // Create a response with one Policy ID TLV for each policy
1276 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1277 if (response == NULL) {
1278 error = ENOMEM;
1279 goto done;
1280 }
1281
1282 u_int8_t *cursor = response;
1283 LIST_FOREACH(policy, &session->policies, chain) {
1284 if (!policy->pending_deletion && cur_policy_index < num_policies) {
1285 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1286 cur_policy_index++;
1287 }
1288 }
1289
1290 error = copyout(response, uap->out_buffer, response_size);
1291 if (error != 0) {
1292 NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1293 goto done;
1294 }
1295
1296 done:
1297 if (response != NULL) {
1298 kfree_data(response, response_size);
1299 response = NULL;
1300 }
1301 *retval = error;
1302
1303 return error;
1304 }
1305
1306
1307 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1308 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1309 {
1310 #pragma unused(uap)
1311 necp_policy_mark_all_for_deletion(session);
1312 *retval = 0;
1313 return 0;
1314 }
1315
1316 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1317 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1318 {
1319 int error = 0;
1320 struct necp_session_policy *policy = NULL;
1321 struct necp_session_policy *temp_policy = NULL;
1322
1323 if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1324 NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1325 error = EINVAL;
1326 goto done;
1327 }
1328
1329 necp_session_priority requested_session_priority = 0;
1330 error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1331 if (error != 0) {
1332 NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1333 goto done;
1334 }
1335
1336 // Enforce special session priorities with entitlements
1337 if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1338 requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1339 requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1340 requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1341 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1342 if (cred_result != 0) {
1343 NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1344 error = EPERM;
1345 goto done;
1346 }
1347 }
1348
1349 if (session->session_priority != requested_session_priority) {
1350 session->session_priority = requested_session_priority;
1351 session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1352 session->dirty = TRUE;
1353
1354 // Mark all policies as needing updates
1355 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1356 policy->pending_update = TRUE;
1357 }
1358 }
1359
1360 done:
1361 *retval = error;
1362 return error;
1363 }
1364
1365 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1366 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1367 {
1368 #pragma unused(uap)
1369 session->proc_locked = TRUE;
1370 *retval = 0;
1371 return 0;
1372 }
1373
1374 static int
necp_session_register_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1375 necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1376 {
1377 int error = 0;
1378 struct necp_service_registration *new_service = NULL;
1379
1380 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1381 NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1382 error = EINVAL;
1383 goto done;
1384 }
1385
1386 uuid_t service_uuid;
1387 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1388 if (error != 0) {
1389 NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1390 goto done;
1391 }
1392
1393 new_service = kalloc_type(struct necp_service_registration,
1394 Z_WAITOK | Z_ZERO | Z_NOFAIL);
1395
1396 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1397 new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1398 LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1399 LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1400 lck_rw_done(&necp_kernel_policy_lock);
1401
1402 done:
1403 *retval = error;
1404 return error;
1405 }
1406
1407 static int
necp_session_unregister_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1408 necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1409 {
1410 int error = 0;
1411 struct necp_service_registration * __single service = NULL;
1412 struct necp_service_registration *temp_service = NULL;
1413 struct necp_uuid_id_mapping *mapping = NULL;
1414
1415 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1416 NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1417 error = EINVAL;
1418 goto done;
1419 }
1420
1421 uuid_t service_uuid;
1422 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1423 if (error != 0) {
1424 NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1425 goto done;
1426 }
1427
1428 // Remove all matching services for this session
1429 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1430 mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1431 if (mapping != NULL) {
1432 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1433 if (service->service_id == mapping->id) {
1434 LIST_REMOVE(service, session_chain);
1435 LIST_REMOVE(service, kernel_chain);
1436 kfree_type(struct necp_service_registration, service);
1437 }
1438 }
1439 necp_remove_uuid_service_id_mapping(service_uuid);
1440 }
1441 lck_rw_done(&necp_kernel_policy_lock);
1442
1443 done:
1444 *retval = error;
1445 return error;
1446 }
1447
1448 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1449 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1450 {
1451 #pragma unused(session)
1452 int error = 0;
1453
1454 if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1455 NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1456 error = EINVAL;
1457 goto done;
1458 }
1459
1460 error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1461 done:
1462 *retval = error;
1463 return error;
1464 }
1465
1466 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1467 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1468 {
1469 int error = 0;
1470 struct net_bloom_filter *bloom_filter = NULL;
1471 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1472 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1473
1474 if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1475 in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1476 uap->in_buffer == 0) {
1477 NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1478 error = EINVAL;
1479 goto done;
1480 }
1481
1482 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1483 NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1484 error = EINVAL;
1485 goto done;
1486 }
1487
1488 bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1489 if (bloom_filter == NULL) {
1490 NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1491 error = ENOMEM;
1492 goto done;
1493 }
1494
1495 error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1496 if (error != 0) {
1497 NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1498 goto done;
1499 }
1500
1501 size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1502 if (expected_filter_size != in_buffer_length) {
1503 NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1504 error = EINVAL;
1505 goto done;
1506 }
1507
1508 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1509 u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1510 lck_rw_done(&necp_kernel_policy_lock);
1511
1512 if (filter_id == 0) {
1513 error = ENOMEM;
1514 } else {
1515 // Bloom filter is taken over by the new filter entry, clear the local pointer
1516 bloom_filter = NULL;
1517
1518 error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1519 if (error != 0) {
1520 NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1521 goto done;
1522 }
1523 }
1524
1525 done:
1526 *retval = error;
1527 if (error != 0 && bloom_filter != NULL) {
1528 uint8_t * __single filter_buffer = (uint8_t *)bloom_filter;
1529 kfree_data(filter_buffer, in_buffer_length);
1530 bloom_filter = NULL;
1531 }
1532 return error;
1533 }
1534
1535 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1536 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1537 {
1538 int error = 0;
1539
1540 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1541 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1542 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1543 error = EINVAL;
1544 goto done;
1545 }
1546
1547 u_int32_t filter_id;
1548 error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1549 if (error != 0) {
1550 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1551 goto done;
1552 }
1553
1554 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1555 bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1556 if (!removed) {
1557 error = ENOENT;
1558 }
1559 lck_rw_done(&necp_kernel_policy_lock);
1560
1561 done:
1562 *retval = error;
1563 return error;
1564 }
1565
1566 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1567 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1568 {
1569 #pragma unused(uap)
1570
1571 struct necp_domain_filter * __single filter = NULL;
1572 struct necp_domain_filter *temp_filter = NULL;
1573 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1574 if (os_ref_release_locked(&filter->refcount) == 0) {
1575 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1576 LIST_REMOVE(filter, chain);
1577 lck_rw_done(&necp_kernel_policy_lock);
1578 LIST_REMOVE(filter, owner_chain);
1579 net_bloom_filter_destroy(filter->filter);
1580 kfree_type(struct necp_domain_filter, filter);
1581 }
1582 }
1583
1584 *retval = 0;
1585 return 0;
1586 }
1587
1588 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1589 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1590 {
1591 struct fileproc * __single fp;
1592 int error = 0;
1593 int return_value = 0;
1594 struct necp_session * __single session = NULL;
1595
1596 error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1597 if (error != 0) {
1598 NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1599 return error;
1600 }
1601
1602 NECP_SESSION_LOCK(session);
1603
1604 if (session->proc_locked) {
1605 // Verify that the calling process is allowed to do actions
1606 uuid_t proc_uuid;
1607 proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1608 if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1609 error = EPERM;
1610 goto done;
1611 }
1612 } else {
1613 // If not locked, update the proc_uuid and proc_pid of the session
1614 proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1615 session->proc_pid = proc_pid(current_proc());
1616 }
1617
1618 u_int32_t action = uap->action;
1619 switch (action) {
1620 case NECP_SESSION_ACTION_POLICY_ADD: {
1621 return_value = necp_session_add_policy(session, uap, retval);
1622 break;
1623 }
1624 case NECP_SESSION_ACTION_POLICY_GET: {
1625 return_value = necp_session_get_policy(session, uap, retval);
1626 break;
1627 }
1628 case NECP_SESSION_ACTION_POLICY_DELETE: {
1629 return_value = necp_session_delete_policy(session, uap, retval);
1630 break;
1631 }
1632 case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1633 return_value = necp_session_apply_all(session, uap, retval);
1634 break;
1635 }
1636 case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1637 return_value = necp_session_list_all(session, uap, retval);
1638 break;
1639 }
1640 case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1641 return_value = necp_session_delete_all(session, uap, retval);
1642 break;
1643 }
1644 case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1645 return_value = necp_session_set_session_priority(session, uap, retval);
1646 break;
1647 }
1648 case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1649 return_value = necp_session_lock_to_process(session, uap, retval);
1650 break;
1651 }
1652 case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1653 return_value = necp_session_register_service(session, uap, retval);
1654 break;
1655 }
1656 case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1657 return_value = necp_session_unregister_service(session, uap, retval);
1658 break;
1659 }
1660 case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1661 return_value = necp_session_dump_all(session, uap, retval);
1662 break;
1663 }
1664 case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1665 return_value = necp_session_add_domain_filter(session, uap, retval);
1666 break;
1667 }
1668 case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1669 return_value = necp_session_remove_domain_filter(session, uap, retval);
1670 break;
1671 }
1672 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1673 return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1674 break;
1675 }
1676 default: {
1677 NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1678 return_value = EINVAL;
1679 break;
1680 }
1681 }
1682
1683 done:
1684 NECP_SESSION_UNLOCK(session);
1685 fp_drop(p, uap->necp_fd, fp, 0);
1686 return return_value;
1687 }
1688
1689 struct necp_resolver_key_state {
1690 const struct ccdigest_info *digest_info;
1691 uint8_t key[CCSHA256_OUTPUT_SIZE];
1692 };
1693 static struct necp_resolver_key_state s_necp_resolver_key_state;
1694
1695 static void
necp_generate_resolver_key(void)1696 necp_generate_resolver_key(void)
1697 {
1698 s_necp_resolver_key_state.digest_info = ccsha256_di();
1699 cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1700 }
1701
1702 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)1703 necp_sign_update_context(const struct ccdigest_info *di,
1704 cchmac_ctx_t ctx,
1705 uuid_t client_id,
1706 u_int32_t sign_type,
1707 u_int8_t *data,
1708 size_t data_length)
1709 {
1710 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1711 const char * __null_terminated context_string = "NECP Resolver Binder";
1712 uint8_t separator = 0;
1713 cchmac_update(di, ctx, sizeof(context), context);
1714 cchmac_update(di, ctx, strlen(context_string), __unsafe_null_terminated_to_indexable(context_string));
1715 cchmac_update(di, ctx, sizeof(separator), &separator);
1716 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1717 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1718 cchmac_update(di, ctx, data_length, data);
1719 }
1720
1721 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)1722 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1723 u_int8_t *data, size_t data_length,
1724 u_int8_t *tag, size_t *out_tag_length)
1725 {
1726 if (s_necp_resolver_key_state.digest_info == NULL) {
1727 return EINVAL;
1728 }
1729
1730 if (data == NULL ||
1731 data_length == 0 ||
1732 tag == NULL ||
1733 out_tag_length == NULL) {
1734 return EINVAL;
1735 }
1736
1737 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1738 if (*out_tag_length < required_tag_length) {
1739 return ERANGE;
1740 }
1741
1742 *out_tag_length = required_tag_length;
1743
1744 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1745 s_necp_resolver_key_state.digest_info->block_size, ctx);
1746 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1747 sizeof(s_necp_resolver_key_state.key),
1748 s_necp_resolver_key_state.key);
1749 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1750 ctx, client_id, sign_type, data, data_length);
1751 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1752
1753 return 0;
1754 }
1755
1756 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)1757 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1758 u_int8_t * __sized_by(data_length)data, size_t data_length,
1759 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1760 {
1761 if (s_necp_resolver_key_state.digest_info == NULL) {
1762 return false;
1763 }
1764
1765 if (data == NULL ||
1766 data_length == 0 ||
1767 tag == NULL ||
1768 tag_length == 0) {
1769 return false;
1770 }
1771
1772 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1773 if (tag_length != required_tag_length) {
1774 return false;
1775 }
1776
1777 uint8_t actual_tag[required_tag_length];
1778
1779 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1780 s_necp_resolver_key_state.digest_info->block_size, ctx);
1781 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1782 sizeof(s_necp_resolver_key_state.key),
1783 s_necp_resolver_key_state.key);
1784 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1785 ctx, client_id, sign_type, data, data_length);
1786 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
1787
1788 return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
1789 }
1790
1791 struct necp_application_id_key_state {
1792 const struct ccdigest_info *digest_info;
1793 uint8_t key[CCSHA256_OUTPUT_SIZE];
1794 };
1795 static struct necp_application_id_key_state s_necp_application_id_key_state;
1796
1797 static void
necp_generate_application_id_key(void)1798 necp_generate_application_id_key(void)
1799 {
1800 s_necp_application_id_key_state.digest_info = ccsha256_di();
1801 cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
1802 }
1803
1804 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)1805 necp_sign_application_id_update_context(const struct ccdigest_info *di,
1806 cchmac_ctx_t ctx,
1807 uuid_t client_id,
1808 u_int32_t sign_type)
1809 {
1810 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1811 const char context_string[] = "NECP Application ID";
1812 uint8_t separator = 0;
1813 cchmac_update(di, ctx, sizeof(context), context);
1814 cchmac_update(di, ctx, sizeof(context_string) - 1, context_string);
1815 cchmac_update(di, ctx, sizeof(separator), &separator);
1816 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1817 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1818 }
1819
1820 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)1821 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
1822 u_int8_t *__counted_by(*out_tag_length)tag, size_t *out_tag_length)
1823 {
1824 if (s_necp_application_id_key_state.digest_info == NULL) {
1825 return EINVAL;
1826 }
1827
1828 if (tag == NULL ||
1829 out_tag_length == NULL) {
1830 return EINVAL;
1831 }
1832
1833 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1834 if (*out_tag_length < required_tag_length) {
1835 return ERANGE;
1836 }
1837
1838 *out_tag_length = required_tag_length;
1839
1840 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1841 s_necp_application_id_key_state.digest_info->block_size, ctx);
1842 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
1843 sizeof(s_necp_application_id_key_state.key),
1844 s_necp_application_id_key_state.key);
1845 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
1846 ctx, client_id, sign_type);
1847 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
1848
1849 return 0;
1850 }
1851
1852 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)1853 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
1854 u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1855 {
1856 if (s_necp_application_id_key_state.digest_info == NULL) {
1857 return false;
1858 }
1859
1860 if (tag == NULL ||
1861 tag_length == 0) {
1862 return false;
1863 }
1864
1865 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1866 if (tag_length != required_tag_length) {
1867 return false;
1868 }
1869
1870 uint8_t actual_tag[required_tag_length];
1871
1872 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1873 s_necp_application_id_key_state.digest_info->block_size, ctx);
1874 cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
1875 sizeof(s_necp_application_id_key_state.key),
1876 s_necp_application_id_key_state.key);
1877 necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
1878 ctx, client_id, sign_type);
1879 cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
1880
1881 return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
1882 }
1883
1884 void
necp_init(void)1885 necp_init(void)
1886 {
1887 necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
1888 necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
1889
1890 necp_client_init();
1891
1892 TAILQ_INIT(&necp_session_list);
1893
1894 LIST_INIT(&necp_kernel_socket_policies);
1895 LIST_INIT(&necp_kernel_ip_output_policies);
1896
1897 LIST_INIT(&necp_account_id_list);
1898
1899 LIST_INIT(&necp_uuid_service_id_list);
1900
1901 LIST_INIT(&necp_registered_service_list);
1902
1903 LIST_INIT(&necp_route_rules);
1904 LIST_INIT(&necp_aggregate_route_rules);
1905
1906 LIST_INIT(&necp_global_domain_filter_list);
1907
1908 necp_generate_resolver_key();
1909 necp_generate_application_id_key();
1910
1911 necp_uuid_app_id_hashtbl = __unsafe_forge_bidi_indexable(struct necp_uuid_id_mapping_head *,
1912 hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask),
1913 NECP_UUID_APP_ID_HASH_SIZE * sizeof(void*));
1914 necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
1915 necp_num_uuid_app_id_mappings = 0;
1916 necp_uuid_app_id_mappings_dirty = FALSE;
1917
1918 necp_kernel_application_policies_condition_mask = 0;
1919 necp_kernel_socket_policies_condition_mask = 0;
1920 necp_kernel_ip_output_policies_condition_mask = 0;
1921
1922 necp_kernel_application_policies_count = 0;
1923 necp_kernel_socket_policies_count = 0;
1924 necp_kernel_socket_policies_non_app_count = 0;
1925 necp_kernel_ip_output_policies_count = 0;
1926 necp_kernel_ip_output_policies_non_id_count = 0;
1927
1928 necp_kernel_socket_policies_gencount = 1;
1929
1930 memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
1931 memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
1932 necp_kernel_socket_policies_app_layer_map = NULL;
1933
1934 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
1935 necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
1936 }
1937
1938 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)1939 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
1940 {
1941 struct kev_msg ev_msg;
1942 memset(&ev_msg, 0, sizeof(ev_msg));
1943
1944 ev_msg.vendor_code = KEV_VENDOR_APPLE;
1945 ev_msg.kev_class = KEV_NETWORK_CLASS;
1946 ev_msg.kev_subclass = KEV_NECP_SUBCLASS;
1947 ev_msg.event_code = KEV_NECP_POLICIES_CHANGED;
1948
1949 ev_msg.dv[0].data_ptr = necp_event_data;
1950 ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
1951 ev_msg.dv[1].data_length = 0;
1952
1953 kev_post_msg(&ev_msg);
1954 }
1955
1956 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)1957 necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor, u_int8_t type, u_int32_t length,
1958 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
1959 {
1960 if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
1961 NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
1962 return false;
1963 }
1964 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1965 if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
1966 (uintptr_t)(next_tlv - buffer) > buffer_length) { // make sure the next TLV has enough room in buffer
1967 NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
1968 length, buffer_length);
1969 return false;
1970 }
1971 return true;
1972 }
1973
1974 u_int8_t * __counted_by(0)
1975 necp_buffer_write_tlv_if_different(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
1976 u_int32_t length, const void * __sized_by(length)value, bool *updated,
1977 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
1978 {
1979 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
1980 u_int8_t * cursor = buffer + (cursor_ - buffer);
1981 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
1982 // If we can't fit this TLV, return the current cursor
1983 return cursor;
1984 }
1985 u_int8_t * __indexable next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1986 if (*updated || *(u_int8_t *)(cursor) != type) {
1987 *(u_int8_t *)(cursor) = type;
1988 *updated = TRUE;
1989 }
1990 if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
1991 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
1992 *updated = TRUE;
1993 }
1994 if (length > 0) {
1995 if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
1996 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
1997 *updated = TRUE;
1998 }
1999 }
2000 return next_tlv;
2001 }
2002
2003 u_int8_t * __counted_by(0)
2004 necp_buffer_write_tlv(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2005 u_int32_t length, const void * __sized_by(length)value,
2006 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2007 {
2008 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2009 u_int8_t * cursor = buffer + (cursor_ - buffer);
2010 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2011 return NULL;
2012 }
2013 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2014 *(u_int8_t *)(cursor) = type;
2015 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2016 if (length > 0) {
2017 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2018 }
2019
2020 return next_tlv;
2021 }
2022
2023 static u_int8_t * __counted_by(0)
2024 necp_buffer_write_tlv_with_flags(u_int8_t * __counted_by(0)cursor_, u_int8_t type, u_int8_t flags,
2025 u_int32_t length, const void * __sized_by(length)value,
2026 u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2027 {
2028 // Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2029 // Add one extra byte to 'length' to account for the flags byte for validation.
2030 u_int8_t * cursor = buffer + (cursor_ - buffer);
2031 if (!necp_buffer_write_tlv_validate(cursor, type, length + 1, buffer, buffer_length)) {
2032 return NULL;
2033 }
2034 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(flags) + sizeof(length) + length);
2035
2036 // TLV with flags format: type, length, flags, value (added 1 byte for the leading flags)
2037 *(u_int8_t *)(cursor) = type;
2038 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2039 *(u_int8_t *)(cursor + sizeof(type) + sizeof(length)) = flags;
2040 if (length > 0) {
2041 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length) + sizeof(flags)), value, length);
2042 }
2043
2044 return next_tlv;
2045 }
2046
2047 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)2048 necp_buffer_get_tlv_type(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2049 {
2050 u_int8_t * __indexable type = NULL;
2051 uint64_t end_offset = 0;
2052
2053 if (buffer == NULL ||
2054 os_add_overflow(tlv_offset, sizeof(u_int8_t), &end_offset) || buffer_length < end_offset) {
2055 return 0;
2056 }
2057
2058 type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
2059 return type ? *type : 0;
2060 }
2061
2062 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)2063 necp_buffer_get_tlv_length(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2064 {
2065 u_int32_t * __indexable length = NULL;
2066 uint64_t end_offset = 0;
2067
2068 if (buffer == NULL ||
2069 os_add_overflow(tlv_offset, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2070 return 0;
2071 }
2072
2073 length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
2074 return length ? *length : 0;
2075 }
2076
2077 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)2078 __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)
2079 {
2080 u_int8_t * __indexable value = NULL;
2081 uint64_t end_offset = 0;
2082
2083 if (buffer == NULL) {
2084 return NULL;
2085 }
2086
2087 u_int32_t length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2088 if (length == 0) {
2089 return NULL;
2090 }
2091
2092 if (os_add3_overflow(tlv_offset, length, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2093 return NULL;
2094 }
2095
2096 if (value_size) {
2097 *value_size = length;
2098 }
2099
2100 value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2101 return value;
2102 }
2103
2104 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)2105 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)
2106 {
2107 if (err != NULL) {
2108 *err = ENOENT;
2109 }
2110 if (offset < 0) {
2111 if (err != NULL) {
2112 *err = EINVAL;
2113 }
2114 return -1;
2115 }
2116 int cursor = offset;
2117 int next_cursor;
2118 u_int32_t curr_length;
2119 u_int8_t curr_type;
2120
2121 while (TRUE) {
2122 if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
2123 return -1;
2124 }
2125 if (!next) {
2126 curr_type = necp_buffer_get_tlv_type(buffer, buffer_length, cursor);
2127 } else {
2128 next = 0;
2129 curr_type = NECP_TLV_NIL;
2130 }
2131 curr_length = necp_buffer_get_tlv_length(buffer, buffer_length, cursor);
2132 if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
2133 return -1;
2134 }
2135
2136 next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
2137 if (curr_type == type) {
2138 // check if entire TLV fits inside buffer
2139 if (((u_int32_t)next_cursor) <= buffer_length) {
2140 if (err != NULL) {
2141 *err = 0;
2142 }
2143 return cursor;
2144 } else {
2145 return -1;
2146 }
2147 }
2148 cursor = next_cursor;
2149 }
2150 }
2151
2152 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)2153 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)
2154 {
2155 int cursor = -1;
2156 if (buffer != NULL) {
2157 cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2158 }
2159 return cursor;
2160 }
2161
2162 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)2163 necp_get_tlv_at_offset(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2164 int tlv_offset, u_int32_t out_buffer_length, void * __indexable out_buffer, u_int32_t *value_size)
2165 {
2166 if (buffer == NULL) {
2167 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2168 return EINVAL;
2169 }
2170
2171 // Handle buffer parsing
2172
2173 // Validate that buffer has enough room for any TLV
2174 if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2175 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2176 buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2177 return EINVAL;
2178 }
2179
2180 // Validate that buffer has enough room for this TLV
2181 u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2182 if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2183 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2184 tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2185 return EINVAL;
2186 }
2187
2188 if (out_buffer != NULL && out_buffer_length > 0) {
2189 // Validate that out buffer is large enough for value
2190 if (out_buffer_length < tlv_length) {
2191 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2192 out_buffer_length, tlv_length);
2193 return EINVAL;
2194 }
2195
2196 // Get value pointer
2197 u_int8_t * __indexable tlv_value = necp_buffer_get_tlv_value(buffer, buffer_length, tlv_offset, NULL);
2198 if (tlv_value == NULL) {
2199 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2200 return ENOENT;
2201 }
2202
2203 // Copy value
2204 memcpy(out_buffer, tlv_value, tlv_length);
2205 }
2206
2207 // Copy out length
2208 if (value_size != NULL) {
2209 *value_size = tlv_length;
2210 }
2211
2212 return 0;
2213 }
2214
2215 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)2216 necp_get_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2217 int offset, u_int8_t type, u_int32_t buff_len, void * __indexable buff, u_int32_t *value_size)
2218 {
2219 int error = 0;
2220
2221 int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2222 if (tlv_offset < 0) {
2223 return error;
2224 }
2225
2226 return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2227 }
2228
2229 // Session Management
2230
2231 static struct necp_session *
necp_create_session(void)2232 necp_create_session(void)
2233 {
2234 struct necp_session *new_session = NULL;
2235
2236 new_session = kalloc_type(struct necp_session,
2237 Z_WAITOK | Z_ZERO | Z_NOFAIL);
2238
2239 new_session->necp_fd_type = necp_fd_type_session;
2240 new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2241 new_session->dirty = FALSE;
2242 LIST_INIT(&new_session->policies);
2243 LIST_INIT(&new_session->services);
2244 LIST_INIT(&new_session->domain_filters);
2245 lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2246
2247 // Take the lock
2248 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2249
2250 // Find the next available control unit
2251 u_int32_t control_unit = 1;
2252 struct necp_session *next_session = NULL;
2253 TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2254 if (next_session->control_unit > control_unit) {
2255 // Found a gap, grab this control unit
2256 break;
2257 }
2258
2259 // Try the next control unit, loop around
2260 control_unit = next_session->control_unit + 1;
2261 }
2262
2263 new_session->control_unit = control_unit;
2264 new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2265
2266 if (next_session != NULL) {
2267 TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2268 } else {
2269 TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2270 }
2271
2272 necp_session_count++;
2273 lck_rw_done(&necp_kernel_policy_lock);
2274
2275 if (necp_debug) {
2276 NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2277 }
2278
2279 return new_session;
2280 }
2281
2282 static void
necp_delete_session(struct necp_session * session)2283 necp_delete_session(struct necp_session *session)
2284 {
2285 if (session != NULL) {
2286 struct necp_service_registration * __single service = NULL;
2287 struct necp_service_registration *temp_service = NULL;
2288 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
2289 LIST_REMOVE(service, session_chain);
2290 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2291 LIST_REMOVE(service, kernel_chain);
2292 lck_rw_done(&necp_kernel_policy_lock);
2293 kfree_type(struct necp_service_registration, service);
2294 }
2295 struct necp_domain_filter * __single filter = NULL;
2296 struct necp_domain_filter *temp_filter = NULL;
2297 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2298 if (os_ref_release_locked(&filter->refcount) == 0) {
2299 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2300 LIST_REMOVE(filter, chain);
2301 lck_rw_done(&necp_kernel_policy_lock);
2302 LIST_REMOVE(filter, owner_chain);
2303 net_bloom_filter_destroy(filter->filter);
2304 kfree_type(struct necp_domain_filter, filter);
2305 }
2306 }
2307 if (necp_debug) {
2308 NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2309 }
2310
2311 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2312 TAILQ_REMOVE(&necp_session_list, session, chain);
2313 necp_session_count--;
2314 lck_rw_done(&necp_kernel_policy_lock);
2315
2316 lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2317 kfree_type(struct necp_session, session);
2318 }
2319 }
2320
2321 // Session Policy Management
2322
2323 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2324 necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2325 {
2326 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2327 }
2328
2329 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2330 necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2331 {
2332 return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2333 }
2334
2335 static inline u_int8_t * __indexable
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2336 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2337 {
2338 return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2339 }
2340
2341 static bool
necp_policy_result_requires_route_rules(u_int8_t * __sized_by (length)buffer,u_int32_t length)2342 necp_policy_result_requires_route_rules(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2343 {
2344 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2345 if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2346 return TRUE;
2347 }
2348 return FALSE;
2349 }
2350
2351 static inline bool
_necp_address_is_valid(struct sockaddr * address)2352 _necp_address_is_valid(struct sockaddr *address)
2353 {
2354 if (address->sa_family == AF_INET) {
2355 return address->sa_len == sizeof(struct sockaddr_in);
2356 } else if (address->sa_family == AF_INET6) {
2357 return address->sa_len == sizeof(struct sockaddr_in6);
2358 } else {
2359 return FALSE;
2360 }
2361 }
2362
2363 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2364
2365 static bool
necp_policy_result_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,bool * is_pass_skip)2366 necp_policy_result_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, bool *is_pass_skip)
2367 {
2368 bool validated = FALSE;
2369 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2370 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2371 *is_pass_skip = FALSE;
2372 switch (type) {
2373 case NECP_POLICY_RESULT_PASS: {
2374 *is_pass_skip = TRUE;
2375 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2376 validated = TRUE;
2377 }
2378 break;
2379 }
2380 case NECP_POLICY_RESULT_DROP: {
2381 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2382 validated = TRUE;
2383 }
2384 break;
2385 }
2386 case NECP_POLICY_RESULT_ROUTE_RULES:
2387 case NECP_POLICY_RESULT_SCOPED_DIRECT:
2388 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2389 validated = TRUE;
2390 break;
2391 }
2392 case NECP_POLICY_RESULT_SKIP:
2393 *is_pass_skip = TRUE;
2394 case NECP_POLICY_RESULT_SOCKET_DIVERT:
2395 case NECP_POLICY_RESULT_SOCKET_FILTER: {
2396 if (parameter_length >= sizeof(u_int32_t)) {
2397 validated = TRUE;
2398 }
2399 break;
2400 }
2401 case NECP_POLICY_RESULT_IP_TUNNEL: {
2402 if (parameter_length > sizeof(u_int32_t)) {
2403 validated = TRUE;
2404 }
2405 break;
2406 }
2407 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2408 if (parameter_length > 0) {
2409 validated = TRUE;
2410 }
2411 break;
2412 }
2413 case NECP_POLICY_RESULT_USE_NETAGENT:
2414 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2415 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2416 if (parameter_length >= sizeof(uuid_t)) {
2417 validated = TRUE;
2418 }
2419 break;
2420 }
2421 default: {
2422 validated = FALSE;
2423 break;
2424 }
2425 }
2426
2427 if (necp_debug) {
2428 NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2429 }
2430
2431 return validated;
2432 }
2433
2434 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2435 necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2436 {
2437 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2438 }
2439
2440 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2441 necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2442 {
2443 return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2444 }
2445
2446 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2447 necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2448 {
2449 return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2450 }
2451
2452 static inline u_int8_t * __indexable
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2453 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2454 {
2455 return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2456 }
2457
2458 static inline bool
necp_policy_condition_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2459 necp_policy_condition_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2460 {
2461 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2462 }
2463
2464 static inline bool
necp_policy_condition_is_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2465 necp_policy_condition_is_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2466 {
2467 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2468 }
2469
2470 static inline bool
necp_policy_condition_is_real_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2471 necp_policy_condition_is_real_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2472 {
2473 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2474 }
2475
2476 static inline bool
necp_policy_condition_requires_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2477 necp_policy_condition_requires_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2478 {
2479 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2480 return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2481 }
2482
2483 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2484 necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2485 {
2486 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2487 u_int32_t condition_length = 0;
2488 pid_t *condition_value = NULL;
2489
2490 if (type == NECP_POLICY_CONDITION_PID) {
2491 condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2492 if (condition_length >= sizeof(pid_t)) {
2493 condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2494 return *condition_value == 0;
2495 }
2496 }
2497 return false;
2498 }
2499
2500 static bool
necp_policy_condition_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,u_int8_t policy_result_type)2501 necp_policy_condition_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, u_int8_t policy_result_type)
2502 {
2503 bool validated = FALSE;
2504 bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2505 policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2506 policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2507 policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2508 policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2509 policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2510 policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2511 policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2512 policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2513 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2514 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2515 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2516 u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2517 switch (type) {
2518 case NECP_POLICY_CONDITION_APPLICATION:
2519 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2520 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2521 condition_length >= sizeof(uuid_t) &&
2522 condition_value != NULL &&
2523 !uuid_is_null(condition_value)) {
2524 validated = TRUE;
2525 }
2526 break;
2527 }
2528 case NECP_POLICY_CONDITION_DOMAIN:
2529 case NECP_POLICY_CONDITION_ACCOUNT:
2530 case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2531 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2532 case NECP_POLICY_CONDITION_URL: {
2533 if (condition_length > 0) {
2534 validated = TRUE;
2535 }
2536 break;
2537 }
2538 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2539 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2540 validated = TRUE;
2541 }
2542 break;
2543 }
2544 case NECP_POLICY_CONDITION_DEFAULT:
2545 case NECP_POLICY_CONDITION_ALL_INTERFACES:
2546 case NECP_POLICY_CONDITION_ENTITLEMENT:
2547 case NECP_POLICY_CONDITION_HAS_CLIENT:
2548 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
2549 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2550 validated = TRUE;
2551 }
2552 break;
2553 }
2554 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2555 if (condition_length == 0 || condition_length >= sizeof(u_int8_t)) {
2556 validated = TRUE;
2557 }
2558 break;
2559 }
2560 case NECP_POLICY_CONDITION_SDK_VERSION: {
2561 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2562 condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2563 validated = TRUE;
2564 }
2565 break;
2566 }
2567 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2568 if (condition_length >= sizeof(u_int16_t)) {
2569 validated = TRUE;
2570 }
2571 break;
2572 }
2573 case NECP_POLICY_CONDITION_PID: {
2574 if (condition_length >= sizeof(pid_t) &&
2575 condition_value != NULL) {
2576 validated = TRUE;
2577 }
2578 break;
2579 }
2580 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2581 if (condition_length >= sizeof(u_int32_t)) {
2582 validated = TRUE;
2583 }
2584 break;
2585 }
2586 case NECP_POLICY_CONDITION_UID:
2587 case NECP_POLICY_CONDITION_REAL_UID: {
2588 if (condition_length >= sizeof(uid_t)) {
2589 validated = TRUE;
2590 }
2591 break;
2592 }
2593 case NECP_POLICY_CONDITION_LOCAL_ADDR:
2594 case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2595 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2596 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2597 validated = TRUE;
2598 }
2599 break;
2600 }
2601 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2602 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2603 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2604 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2605 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2606 validated = TRUE;
2607 }
2608 break;
2609 }
2610 case NECP_POLICY_CONDITION_AGENT_TYPE: {
2611 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2612 condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2613 validated = TRUE;
2614 }
2615 break;
2616 }
2617 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2618 if (condition_length >= sizeof(u_int16_t)) {
2619 validated = TRUE;
2620 }
2621 break;
2622 }
2623 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2624 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2625 if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2626 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2627 validated = TRUE;
2628 }
2629 break;
2630 }
2631 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2632 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2633 if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2634 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2635 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2636 validated = TRUE;
2637 }
2638 break;
2639 }
2640 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2641 if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2642 validated = TRUE;
2643 }
2644 break;
2645 }
2646 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2647 validated = TRUE;
2648 break;
2649 }
2650 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2651 validated = TRUE;
2652 break;
2653 }
2654 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2655 if (condition_length >= sizeof(u_int16_t)) {
2656 u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2657 if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2658 validated = TRUE;
2659 }
2660 }
2661 break;
2662 }
2663 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2664 validated = TRUE;
2665 break;
2666 }
2667 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
2668 validated = TRUE;
2669 break;
2670 }
2671 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2672 validated = TRUE;
2673 break;
2674 }
2675 case NECP_POLICY_CONDITION_SCHEME_PORT: {
2676 if (condition_length >= sizeof(u_int16_t)) {
2677 validated = TRUE;
2678 }
2679 break;
2680 }
2681 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2682 if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2683 validated = TRUE;
2684 }
2685 break;
2686 }
2687 default: {
2688 validated = FALSE;
2689 break;
2690 }
2691 }
2692
2693 if (necp_debug) {
2694 NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2695 }
2696
2697 return validated;
2698 }
2699
2700 static bool
necp_policy_route_rule_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2701 necp_policy_route_rule_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2702 {
2703 return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2704 necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2705 }
2706
2707 static bool
necp_policy_route_rule_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2708 necp_policy_route_rule_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2709 {
2710 bool validated = FALSE;
2711 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2712 switch (type) {
2713 case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2714 validated = TRUE;
2715 break;
2716 }
2717 case NECP_ROUTE_RULE_DENY_INTERFACE: {
2718 validated = TRUE;
2719 break;
2720 }
2721 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2722 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2723 validated = (rule_length >= sizeof(u_int32_t));
2724 break;
2725 }
2726 case NECP_ROUTE_RULE_QOS_MARKING: {
2727 validated = TRUE;
2728 break;
2729 }
2730 case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2731 validated = TRUE;
2732 break;
2733 }
2734 case NECP_ROUTE_RULE_USE_NETAGENT:
2735 case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2736 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2737 validated = (rule_length >= sizeof(uuid_t));
2738 break;
2739 }
2740 case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2741 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2742 validated = (rule_length >= sizeof(uint32_t));
2743 break;
2744 }
2745 default: {
2746 validated = FALSE;
2747 break;
2748 }
2749 }
2750
2751 if (necp_debug) {
2752 NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2753 }
2754
2755 return validated;
2756 }
2757
2758 static int
necp_get_posix_error_for_necp_error(int response_error)2759 necp_get_posix_error_for_necp_error(int response_error)
2760 {
2761 switch (response_error) {
2762 case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2763 case NECP_ERROR_INVALID_TLV:
2764 case NECP_ERROR_POLICY_RESULT_INVALID:
2765 case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2766 case NECP_ERROR_ROUTE_RULES_INVALID: {
2767 return EINVAL;
2768 }
2769 case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2770 return ENOENT;
2771 }
2772 case NECP_ERROR_INVALID_PROCESS: {
2773 return EPERM;
2774 }
2775 case NECP_ERROR_INTERNAL:
2776 default: {
2777 return ENOMEM;
2778 }
2779 }
2780 }
2781
2782 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)2783 necp_handle_policy_add(struct necp_session *session,
2784 u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
2785 {
2786 bool has_default_condition = FALSE;
2787 bool has_non_default_condition = FALSE;
2788 bool has_application_condition = FALSE;
2789 bool has_real_application_condition = FALSE;
2790 bool requires_application_condition = FALSE;
2791 bool has_kernel_pid = FALSE;
2792 bool is_pass_skip = FALSE;
2793 u_int32_t conditions_array_size = 0;
2794 u_int8_t *conditions_array = NULL;
2795 int conditions_array_cursor;
2796
2797 bool has_default_route_rule = FALSE;
2798 u_int32_t route_rules_array_size = 0;
2799 u_int8_t *route_rules_array = NULL;
2800 int route_rules_array_cursor;
2801
2802 int cursor;
2803 int error = 0;
2804 u_int32_t response_error = NECP_ERROR_INTERNAL;
2805
2806 necp_policy_order order = 0;
2807 struct necp_session_policy *policy = NULL;
2808 u_int32_t policy_result_size = 0;
2809 u_int8_t *policy_result = NULL;
2810
2811 // Read policy order
2812 error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
2813 if (error) {
2814 NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
2815 response_error = NECP_ERROR_INVALID_TLV;
2816 goto fail;
2817 }
2818
2819 // Read policy result
2820 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
2821 if (error || cursor < 0) {
2822 NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
2823 response_error = NECP_ERROR_INVALID_TLV;
2824 goto fail;
2825 }
2826
2827 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
2828 if (error || policy_result_size == 0) {
2829 NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
2830 response_error = NECP_ERROR_INVALID_TLV;
2831 goto fail;
2832 }
2833 if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
2834 NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
2835 response_error = NECP_ERROR_INVALID_TLV;
2836 goto fail;
2837 }
2838 policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
2839 if (policy_result == NULL) {
2840 NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
2841 response_error = NECP_ERROR_INTERNAL;
2842 goto fail;
2843 }
2844 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
2845 if (error) {
2846 NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
2847 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2848 goto fail;
2849 }
2850 if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
2851 NECPLOG0(LOG_ERR, "Failed to validate policy result");
2852 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2853 goto fail;
2854 }
2855
2856 if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
2857 // Read route rules conditions
2858
2859 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
2860 cursor >= 0;
2861 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
2862 u_int32_t route_rule_size = 0;
2863 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
2864 if (os_add_overflow(route_rules_array_size,
2865 (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
2866 &route_rules_array_size)) {
2867 NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
2868 response_error = NECP_ERROR_INVALID_TLV;
2869 goto fail;
2870 }
2871 }
2872
2873 if (route_rules_array_size == 0) {
2874 NECPLOG0(LOG_ERR, "Failed to get policy route rules");
2875 response_error = NECP_ERROR_INVALID_TLV;
2876 goto fail;
2877 }
2878 if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
2879 NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
2880 response_error = NECP_ERROR_INVALID_TLV;
2881 goto fail;
2882 }
2883 route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
2884 if (route_rules_array == NULL) {
2885 NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
2886 response_error = NECP_ERROR_INTERNAL;
2887 goto fail;
2888 }
2889
2890 route_rules_array_cursor = 0;
2891 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
2892 cursor >= 0;
2893 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
2894 u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
2895 u_int32_t route_rule_size = 0;
2896 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
2897 if (route_rule_size > 0 &&
2898 (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
2899 // Add type
2900 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
2901 route_rules_array_cursor += sizeof(route_rule_type);
2902
2903 // Add length
2904 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
2905 route_rules_array_cursor += sizeof(route_rule_size);
2906
2907 // Add value
2908 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
2909
2910 if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
2911 NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
2912 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2913 goto fail;
2914 }
2915
2916 if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
2917 if (has_default_route_rule) {
2918 NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
2919 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2920 goto fail;
2921 }
2922 has_default_route_rule = TRUE;
2923 }
2924
2925 route_rules_array_cursor += route_rule_size;
2926 }
2927 }
2928 }
2929
2930 // Read policy conditions
2931 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
2932 cursor >= 0;
2933 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
2934 u_int32_t condition_size = 0;
2935 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
2936
2937 if (condition_size > 0) {
2938 if (os_add_overflow(conditions_array_size,
2939 (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
2940 &conditions_array_size)) {
2941 NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
2942 response_error = NECP_ERROR_INVALID_TLV;
2943 goto fail;
2944 }
2945 }
2946 }
2947
2948 if (conditions_array_size == 0) {
2949 NECPLOG0(LOG_ERR, "Failed to get policy conditions");
2950 response_error = NECP_ERROR_INVALID_TLV;
2951 goto fail;
2952 }
2953 if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
2954 NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
2955 response_error = NECP_ERROR_INVALID_TLV;
2956 goto fail;
2957 }
2958 conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
2959 if (conditions_array == NULL) {
2960 NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
2961 response_error = NECP_ERROR_INTERNAL;
2962 goto fail;
2963 }
2964
2965 conditions_array_cursor = 0;
2966 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
2967 cursor >= 0;
2968 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
2969 u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
2970 u_int32_t condition_size = 0;
2971 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
2972 if (condition_size > 0 &&
2973 (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
2974 // Add type
2975 memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
2976 conditions_array_cursor += sizeof(condition_type);
2977
2978 // Add length
2979 memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
2980 conditions_array_cursor += sizeof(condition_size);
2981
2982 // Add value
2983 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
2984 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))) {
2985 NECPLOG0(LOG_ERR, "Failed to validate policy condition");
2986 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2987 goto fail;
2988 }
2989
2990 if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
2991 has_default_condition = TRUE;
2992 } else {
2993 has_non_default_condition = TRUE;
2994 }
2995 if (has_default_condition && has_non_default_condition) {
2996 NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
2997 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2998 goto fail;
2999 }
3000
3001 if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
3002 has_application_condition = TRUE;
3003 }
3004
3005 if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
3006 has_real_application_condition = TRUE;
3007 }
3008
3009 if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
3010 requires_application_condition = TRUE;
3011 }
3012
3013 if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
3014 has_kernel_pid = TRUE;
3015 }
3016
3017 conditions_array_cursor += condition_size;
3018 }
3019 }
3020
3021 if (requires_application_condition && !has_application_condition) {
3022 NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
3023 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3024 goto fail;
3025 }
3026
3027 if (has_kernel_pid && !is_pass_skip) {
3028 NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
3029 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3030 goto fail;
3031 }
3032
3033 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) {
3034 response_error = NECP_ERROR_INTERNAL;
3035 goto fail;
3036 }
3037
3038 return policy->local_id;
3039
3040 fail:
3041 if (policy_result != NULL) {
3042 kfree_data_sized_by(policy_result, policy_result_size);
3043 }
3044 if (conditions_array != NULL) {
3045 kfree_data_sized_by(conditions_array, conditions_array_size);
3046 }
3047 if (route_rules_array != NULL) {
3048 kfree_data_sized_by(route_rules_array, route_rules_array_size);
3049 }
3050
3051 if (return_error != NULL) {
3052 *return_error = necp_get_posix_error_for_necp_error(response_error);
3053 }
3054 return 0;
3055 }
3056
3057 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)3058 necp_policy_get_new_id(struct necp_session *session)
3059 {
3060 session->last_policy_id++;
3061 if (session->last_policy_id < 1) {
3062 session->last_policy_id = 1;
3063 }
3064
3065 necp_policy_id newid = session->last_policy_id;
3066
3067 if (newid == 0) {
3068 NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
3069 return 0;
3070 }
3071
3072 return newid;
3073 }
3074
3075 /*
3076 * For the policy dump response this is the structure:
3077 *
3078 * <NECP_PACKET_HEADER>
3079 * {
3080 * type : NECP_TLV_POLICY_DUMP
3081 * length : ...
3082 * value :
3083 * {
3084 * {
3085 * type : NECP_TLV_POLICY_ID
3086 * len : ...
3087 * value : ...
3088 * }
3089 * {
3090 * type : NECP_TLV_POLICY_ORDER
3091 * len : ...
3092 * value : ...
3093 * }
3094 * {
3095 * type : NECP_TLV_POLICY_RESULT_STRING
3096 * len : ...
3097 * value : ...
3098 * }
3099 * {
3100 * type : NECP_TLV_POLICY_OWNER
3101 * len : ...
3102 * value : ...
3103 * }
3104 * {
3105 * type : NECP_TLV_POLICY_CONDITION
3106 * len : ...
3107 * value :
3108 * {
3109 * {
3110 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3111 * len : ...
3112 * value : ...
3113 * }
3114 * {
3115 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3116 * len : ...
3117 * value : ...
3118 * }
3119 * ...
3120 * }
3121 * }
3122 * }
3123 * }
3124 * {
3125 * type : NECP_TLV_POLICY_DUMP
3126 * length : ...
3127 * value :
3128 * {
3129 * {
3130 * type : NECP_TLV_POLICY_ID
3131 * len : ...
3132 * value : ...
3133 * }
3134 * {
3135 * type : NECP_TLV_POLICY_ORDER
3136 * len : ...
3137 * value : ...
3138 * }
3139 * {
3140 * type : NECP_TLV_POLICY_RESULT_STRING
3141 * len : ...
3142 * value : ...
3143 * }
3144 * {
3145 * type : NECP_TLV_POLICY_OWNER
3146 * len : ...
3147 * value : ...
3148 * }
3149 * {
3150 * type : NECP_TLV_POLICY_CONDITION
3151 * len : ...
3152 * value :
3153 * {
3154 * {
3155 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
3156 * len : ...
3157 * value : ...
3158 * }
3159 * {
3160 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3161 * len : ...
3162 * value : ...
3163 * }
3164 * ...
3165 * }
3166 * }
3167 * }
3168 * }
3169 * ...
3170 */
3171 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3172 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3173 {
3174 struct necp_kernel_socket_policy * __single policy = NULL;
3175 int policy_i;
3176 int policy_count = 0;
3177 u_int8_t * __indexable * __indexable tlv_buffer_pointers = NULL;
3178 u_int32_t * __indexable tlv_buffer_lengths = NULL;
3179 u_int32_t total_tlv_len = 0;
3180 u_int8_t * __indexable result_buf = NULL;
3181 u_int8_t *result_buf_cursor = result_buf;
3182 char result_string[MAX_RESULT_STRING_LEN];
3183 char proc_name_string[MAXCOMLEN + 1];
3184
3185 int error_code = 0;
3186 bool error_occured = false;
3187 u_int32_t response_error = NECP_ERROR_INTERNAL;
3188
3189 #define REPORT_ERROR(error) error_occured = true; \
3190 response_error = error; \
3191 goto done
3192
3193 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
3194 REPORT_ERROR(error)
3195
3196 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3197 if (cred_result != 0) {
3198 NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3199 REPORT_ERROR(NECP_ERROR_INTERNAL);
3200 }
3201
3202 // LOCK
3203 lck_rw_lock_shared(&necp_kernel_policy_lock);
3204
3205 if (necp_debug) {
3206 NECPLOG0(LOG_DEBUG, "Gathering policies");
3207 }
3208
3209 policy_count = necp_kernel_application_policies_count;
3210
3211 tlv_buffer_pointers = kalloc_type(u_int8_t * __indexable, policy_count, M_WAITOK | Z_ZERO);
3212 if (tlv_buffer_pointers == NULL) {
3213 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3214 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3215 }
3216
3217 tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3218 if (tlv_buffer_lengths == NULL) {
3219 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3220 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3221 }
3222
3223 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3224 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3225
3226 memset(result_string, 0, MAX_RESULT_STRING_LEN);
3227 memset(proc_name_string, 0, MAXCOMLEN + 1);
3228
3229 necp_get_result_description(result_string, policy->result, policy->result_parameter);
3230 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3231
3232 u_int16_t proc_name_len = strbuflen(proc_name_string, sizeof(proc_name_string) - 1) + 1;
3233 u_int16_t result_string_len = strbuflen(result_string, sizeof(result_string) - 1) + 1;
3234
3235 if (necp_debug) {
3236 NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3237 }
3238
3239 u_int32_t total_allocated_bytes = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) + // NECP_TLV_POLICY_ID
3240 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) + // NECP_TLV_POLICY_ORDER
3241 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) + // NECP_TLV_POLICY_SESSION_ORDER
3242 sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len + // NECP_TLV_POLICY_RESULT_STRING
3243 sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len + // NECP_TLV_POLICY_OWNER
3244 sizeof(u_int8_t) + sizeof(u_int32_t); // NECP_TLV_POLICY_CONDITION
3245
3246 // We now traverse the condition_mask to see how much space we need to allocate
3247 u_int64_t condition_mask = policy->condition_mask;
3248 u_int64_t condition_negated_mask = policy->condition_negated_mask;
3249 u_int8_t num_conditions = 0;
3250 struct necp_string_id_mapping *account_id_entry = NULL;
3251 char if_name[IFXNAMSIZ];
3252 u_int32_t condition_tlv_length = 0;
3253 memset(if_name, 0, sizeof(if_name));
3254
3255 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3256 num_conditions++;
3257 } else {
3258 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3259 num_conditions++;
3260 }
3261 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3262 num_conditions++;
3263 }
3264 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3265 snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3266 condition_tlv_length += strbuflen(if_name, sizeof(if_name) - 1) + 1;
3267 num_conditions++;
3268 }
3269 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3270 condition_tlv_length += sizeof(policy->cond_protocol);
3271 num_conditions++;
3272 }
3273 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3274 condition_tlv_length += sizeof(uuid_t);
3275 num_conditions++;
3276 }
3277 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3278 condition_tlv_length += sizeof(uuid_t);
3279 num_conditions++;
3280 }
3281 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3282 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3283 u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3284 condition_tlv_length += domain_len;
3285 num_conditions++;
3286 }
3287 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3288 condition_tlv_length += sizeof(u_int32_t);
3289 num_conditions++;
3290 }
3291 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3292 u_int32_t url_len = strlen(policy->cond_url) + 1;
3293 condition_tlv_length += url_len;
3294 num_conditions++;
3295 }
3296 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3297 account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3298 u_int32_t account_id_len = 0;
3299 if (account_id_entry) {
3300 account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3301 }
3302 condition_tlv_length += account_id_len;
3303 num_conditions++;
3304 }
3305 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3306 condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3307 num_conditions++;
3308 }
3309 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3310 condition_tlv_length += sizeof(uid_t);
3311 num_conditions++;
3312 }
3313 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3314 condition_tlv_length += sizeof(uid_t);
3315 num_conditions++;
3316 }
3317 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3318 condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3319 num_conditions++;
3320 }
3321 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3322 num_conditions++;
3323 }
3324 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3325 u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3326 condition_tlv_length += entitlement_len;
3327 num_conditions++;
3328 }
3329 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3330 num_conditions++;
3331 }
3332 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3333 num_conditions++;
3334 }
3335 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3336 condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3337 num_conditions++;
3338 }
3339 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3340 condition_tlv_length += sizeof(policy->cond_local_networks_flags);
3341 num_conditions++;
3342 }
3343 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3344 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3345 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3346 } else {
3347 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3348 }
3349 num_conditions++;
3350 }
3351 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3352 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3353 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3354 } else {
3355 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3356 }
3357 num_conditions++;
3358 }
3359 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3360 condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3361 num_conditions++;
3362 }
3363 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3364 condition_tlv_length += sizeof(u_int32_t);
3365 num_conditions++;
3366 }
3367 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3368 num_conditions++;
3369 }
3370 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3371 num_conditions++;
3372 }
3373 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3374 u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3375 condition_tlv_length += identifier_len;
3376 num_conditions++;
3377 }
3378 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3379 condition_tlv_length += sizeof(u_int16_t);
3380 num_conditions++;
3381 }
3382 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3383 num_conditions++;
3384 }
3385 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3386 num_conditions++;
3387 }
3388 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3389 condition_tlv_length += sizeof(u_int16_t);
3390 num_conditions++;
3391 }
3392 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3393 condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3394 num_conditions++;
3395 }
3396 }
3397
3398 // These are for the condition TLVs (id, length, flags). The space for "value" is already accounted for above.
3399 condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int8_t));
3400 total_allocated_bytes += condition_tlv_length;
3401
3402 u_int8_t * __indexable tlv_buffer;
3403 tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3404 if (tlv_buffer == NULL) {
3405 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3406 continue;
3407 }
3408
3409 u_int8_t *cursor = tlv_buffer;
3410 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3411 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3412 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3413 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3414 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3415
3416 #define N_QUICK 256
3417 u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3418
3419 u_int8_t * __indexable cond_buf; // To be used for condition TLVs
3420 if (condition_tlv_length <= N_QUICK) {
3421 cond_buf = q_cond_buf;
3422 } else {
3423 cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3424 if (cond_buf == NULL) {
3425 NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3426 kfree_data(tlv_buffer, total_allocated_bytes);
3427 continue;
3428 }
3429 }
3430
3431 memset(cond_buf, 0, condition_tlv_length);
3432 u_int8_t *cond_buf_cursor = cond_buf;
3433 u_int8_t cond_flags = 0;
3434 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3435 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3436 } else {
3437 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3438 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3439 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);
3440 }
3441 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3442 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3443 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);
3444 }
3445 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3446 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3447 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);
3448 }
3449 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3450 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3451 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,
3452 if_name, cond_buf, condition_tlv_length);
3453 }
3454 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3455 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3456 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,
3457 cond_buf, condition_tlv_length);
3458 }
3459 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3460 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3461 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3462 if (entry != NULL) {
3463 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3464 cond_buf, condition_tlv_length);
3465 }
3466 }
3467 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3468 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3469 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3470 if (entry != NULL) {
3471 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3472 cond_buf, condition_tlv_length);
3473 }
3474 }
3475 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3476 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3477 cond_flags = ((condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) || (condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3478 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);
3479 }
3480 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3481 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3482 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,
3483 cond_buf, condition_tlv_length);
3484 }
3485 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3486 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_URL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3487 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);
3488 }
3489 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3490 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3491 if (account_id_entry != NULL) {
3492 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);
3493 }
3494 }
3495 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3496 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3497 uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3498 memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3499 memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3500 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PID, cond_flags, sizeof(pid_buffer), &pid_buffer,
3501 cond_buf, condition_tlv_length);
3502 }
3503 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3504 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3505 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,
3506 cond_buf, condition_tlv_length);
3507 }
3508 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3509 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3510 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,
3511 cond_buf, condition_tlv_length);
3512 }
3513 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3514 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3515 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,
3516 cond_buf, condition_tlv_length);
3517 }
3518 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3519 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3520 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, 0, "",
3521 cond_buf, condition_tlv_length);
3522 }
3523 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3524 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3525 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);
3526 }
3527 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3528 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3529 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);
3530 }
3531 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3532 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3533 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);
3534 }
3535 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3536 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SDK_VERSION) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3537 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION, cond_flags,
3538 sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3539 cond_buf, condition_tlv_length);
3540 }
3541 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3542 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3543 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3544 struct necp_policy_condition_addr_range range;
3545 memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3546 memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3547 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, cond_flags, sizeof(range), &range,
3548 cond_buf, condition_tlv_length);
3549 } else {
3550 struct necp_policy_condition_addr addr;
3551 addr.prefix = policy->cond_local_prefix;
3552 memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3553 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, cond_flags, sizeof(addr), &addr,
3554 cond_buf, condition_tlv_length);
3555 }
3556 }
3557 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3558 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3559 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3560 struct necp_policy_condition_addr_range range;
3561 memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3562 memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3563 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, cond_flags, sizeof(range), &range,
3564 cond_buf, condition_tlv_length);
3565 } else {
3566 struct necp_policy_condition_addr addr;
3567 addr.prefix = policy->cond_remote_prefix;
3568 memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3569 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, cond_flags, sizeof(addr), &addr,
3570 cond_buf, condition_tlv_length);
3571 }
3572 }
3573 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3574 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3575 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE, cond_flags,
3576 sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3577 cond_buf, condition_tlv_length);
3578 }
3579 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3580 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3581 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);
3582 }
3583 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3584 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3585 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);
3586 }
3587 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3588 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3589 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);
3590 }
3591 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3592 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3593 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);
3594 }
3595 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3596 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3597 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);
3598 }
3599 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3600 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3601 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);
3602 }
3603 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3604 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3605 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);
3606 }
3607 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3608 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3609 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);
3610 }
3611 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3612 cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3613 uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3614 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3615 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3616 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3617 cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, cond_flags, sizeof(flags), &flags,
3618 cond_buf, condition_tlv_length);
3619 }
3620 }
3621
3622 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3623 if (cond_buf != q_cond_buf) {
3624 kfree_data(cond_buf, condition_tlv_length);
3625 }
3626
3627 tlv_buffer_pointers[policy_i] = tlv_buffer;
3628 tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3629
3630 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
3631 total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3632 }
3633
3634 // UNLOCK
3635 lck_rw_done(&necp_kernel_policy_lock);
3636
3637 // Copy out
3638 if (out_buffer != 0) {
3639 if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3640 NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3641 REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3642 }
3643
3644 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3645 result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3646 if (result_buf == NULL) {
3647 NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3648 REPORT_ERROR(NECP_ERROR_INTERNAL);
3649 }
3650
3651 // Add four bytes for total length at the start
3652 memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3653
3654 // Copy the TLVs
3655 result_buf_cursor = result_buf + sizeof(u_int32_t);
3656 for (int i = 0; i < policy_count; i++) {
3657 if (tlv_buffer_pointers[i] != NULL) {
3658 result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3659 result_buf, total_tlv_len + sizeof(u_int32_t));
3660 }
3661 }
3662
3663 int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3664 if (copy_error) {
3665 NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3666 REPORT_ERROR(NECP_ERROR_INTERNAL);
3667 }
3668 }
3669
3670 done:
3671
3672 if (error_occured) {
3673 error_code = necp_get_posix_error_for_necp_error(response_error);
3674 }
3675
3676 if (result_buf != NULL) {
3677 kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3678 }
3679
3680 if (tlv_buffer_pointers != NULL) {
3681 for (int i = 0; i < policy_count; i++) {
3682 if (tlv_buffer_pointers[i] != NULL) {
3683 kfree_data_addr(tlv_buffer_pointers[i]);
3684 tlv_buffer_pointers[i] = NULL;
3685 }
3686 }
3687 kfree_type(u_int8_t * __indexable, policy_count, tlv_buffer_pointers);
3688 }
3689
3690 if (tlv_buffer_lengths != NULL) {
3691 kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3692 }
3693 #undef N_QUICK
3694 #undef RESET_COND_BUF
3695 #undef REPORT_ERROR
3696 #undef UNLOCK_AND_REPORT_ERROR
3697
3698 return error_code;
3699 }
3700
3701 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)3702 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)
3703 {
3704 struct necp_session_policy *new_policy = NULL;
3705 struct necp_session_policy *tmp_policy = NULL;
3706
3707 if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3708 goto done;
3709 }
3710
3711 new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3712 new_policy->applied = FALSE;
3713 new_policy->pending_deletion = FALSE;
3714 new_policy->pending_update = FALSE;
3715 new_policy->order = order;
3716 new_policy->conditions = conditions_array;
3717 new_policy->conditions_size = conditions_array_size;
3718 new_policy->route_rules = route_rules_array;
3719 new_policy->route_rules_size = route_rules_array_size;
3720 new_policy->result = result;
3721 new_policy->result_size = result_size;
3722 new_policy->local_id = necp_policy_get_new_id(session);
3723
3724 LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3725
3726 session->dirty = TRUE;
3727
3728 if (necp_debug) {
3729 NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3730 }
3731 done:
3732 return new_policy;
3733 }
3734
3735 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3736 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3737 {
3738 struct necp_session_policy *policy = NULL;
3739 if (policy_id == 0) {
3740 return NULL;
3741 }
3742
3743 LIST_FOREACH(policy, &session->policies, chain) {
3744 if (policy->local_id == policy_id) {
3745 return policy;
3746 }
3747 }
3748
3749 return NULL;
3750 }
3751
3752 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3753 necp_policy_get_result_type(struct necp_session_policy *policy)
3754 {
3755 return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3756 }
3757
3758 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3759 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3760 {
3761 return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3762 }
3763
3764 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)3765 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)
3766 {
3767 if (policy) {
3768 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3769 if (parameter_buffer_length >= parameter_length) {
3770 u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3771 if (parameter && parameter_buffer) {
3772 memcpy(parameter_buffer, parameter, parameter_length);
3773 return TRUE;
3774 }
3775 }
3776 }
3777
3778 return FALSE;
3779 }
3780
3781 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)3782 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
3783 {
3784 if (session == NULL || policy == NULL) {
3785 return FALSE;
3786 }
3787
3788 policy->pending_deletion = TRUE;
3789 session->dirty = TRUE;
3790
3791 if (necp_debug) {
3792 NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
3793 }
3794 return TRUE;
3795 }
3796
3797 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)3798 necp_policy_mark_all_for_deletion(struct necp_session *session)
3799 {
3800 struct necp_session_policy *policy = NULL;
3801 struct necp_session_policy *temp_policy = NULL;
3802
3803 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
3804 necp_policy_mark_for_deletion(session, policy);
3805 }
3806
3807 return TRUE;
3808 }
3809
3810 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)3811 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
3812 {
3813 if (session == NULL || policy == NULL) {
3814 return FALSE;
3815 }
3816
3817 LIST_REMOVE(policy, chain);
3818
3819 if (policy->result) {
3820 kfree_data_sized_by(policy->result, policy->result_size);
3821 policy->result = NULL;
3822 policy->result_size = 0;
3823 }
3824
3825 if (policy->conditions) {
3826 kfree_data_sized_by(policy->conditions, policy->conditions_size);
3827 policy->conditions = NULL;
3828 policy->conditions_size = 0;
3829 }
3830
3831 if (policy->route_rules) {
3832 kfree_data_sized_by(policy->route_rules, policy->route_rules_size);
3833 policy->route_rules = NULL;
3834 policy->route_rules_size = 0;
3835 }
3836
3837 zfree(necp_session_policy_zone, policy);
3838
3839 if (necp_debug) {
3840 NECPLOG0(LOG_DEBUG, "Removed NECP policy");
3841 }
3842 return TRUE;
3843 }
3844
3845 static bool
necp_policy_unapply(struct necp_session_policy * policy)3846 necp_policy_unapply(struct necp_session_policy *policy)
3847 {
3848 int i = 0;
3849 if (policy == NULL) {
3850 return FALSE;
3851 }
3852
3853 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3854
3855 // Release local uuid mappings
3856 if (!uuid_is_null(policy->applied_app_uuid)) {
3857 bool removed_mapping = FALSE;
3858 if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
3859 necp_uuid_app_id_mappings_dirty = TRUE;
3860 necp_num_uuid_app_id_mappings--;
3861 }
3862 uuid_clear(policy->applied_app_uuid);
3863 }
3864 if (!uuid_is_null(policy->applied_real_app_uuid)) {
3865 necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
3866 uuid_clear(policy->applied_real_app_uuid);
3867 }
3868 if (!uuid_is_null(policy->applied_result_uuid)) {
3869 necp_remove_uuid_service_id_mapping(policy->applied_result_uuid);
3870 uuid_clear(policy->applied_result_uuid);
3871 }
3872
3873 // Release string mappings
3874 if (policy->applied_account != NULL) {
3875 necp_remove_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(policy->applied_account));
3876 kfree_data_sized_by(policy->applied_account, policy->applied_account_size);
3877 policy->applied_account = NULL;
3878 policy->applied_account_size = 0;
3879 }
3880
3881 // Release route rule
3882 if (policy->applied_route_rules_id != 0) {
3883 necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
3884 policy->applied_route_rules_id = 0;
3885 }
3886
3887 // Remove socket policies
3888 for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
3889 if (policy->kernel_socket_policies[i] != 0) {
3890 necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
3891 policy->kernel_socket_policies[i] = 0;
3892 }
3893 }
3894
3895 // Remove IP output policies
3896 for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
3897 if (policy->kernel_ip_output_policies[i] != 0) {
3898 necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
3899 policy->kernel_ip_output_policies[i] = 0;
3900 }
3901 }
3902
3903 policy->applied = FALSE;
3904
3905 return TRUE;
3906 }
3907
3908 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
3909 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
3910 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
3911 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
3912 struct necp_policy_result_ip_tunnel {
3913 u_int32_t secondary_result;
3914 char interface_name[IFXNAMSIZ];
3915 } __attribute__((__packed__));
3916
3917 struct necp_policy_result_service {
3918 uuid_t identifier;
3919 u_int32_t data;
3920 } __attribute__((__packed__));
3921
3922 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy)3923 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
3924 {
3925 bool socket_only_conditions = FALSE;
3926 bool socket_ip_conditions = FALSE;
3927
3928 bool socket_layer_non_id_conditions = FALSE;
3929 bool ip_output_layer_non_id_conditions = FALSE;
3930 bool ip_output_layer_non_id_only = FALSE;
3931 bool ip_output_layer_id_condition = FALSE;
3932 bool ip_output_layer_tunnel_condition_from_id = FALSE;
3933 bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
3934 necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
3935
3936 u_int64_t master_condition_mask = 0;
3937 u_int64_t master_condition_negated_mask = 0;
3938 ifnet_t __single cond_bound_interface = NULL;
3939 u_int32_t cond_account_id = 0;
3940 char *cond_domain __null_terminated = NULL;
3941 u_int32_t cond_domain_filter = 0;
3942 char *cond_url __null_terminated = NULL;
3943 char *cond_custom_entitlement __null_terminated = NULL;
3944 char *cond_signing_identifier __null_terminated = NULL;
3945 pid_t cond_pid = 0;
3946 int32_t cond_pid_version = 0;
3947 uid_t cond_uid = 0;
3948 uid_t cond_real_uid = 0;
3949 necp_app_id cond_app_id = 0;
3950 necp_app_id cond_real_app_id = 0;
3951 struct necp_policy_condition_tc_range cond_traffic_class;
3952 cond_traffic_class.start_tc = 0;
3953 cond_traffic_class.end_tc = 0;
3954 u_int16_t cond_protocol = 0;
3955 union necp_sockaddr_union cond_local_start;
3956 union necp_sockaddr_union cond_local_end;
3957 u_int8_t cond_local_prefix = 0;
3958 union necp_sockaddr_union cond_remote_start;
3959 union necp_sockaddr_union cond_remote_end;
3960 u_int8_t cond_remote_prefix = 0;
3961 u_int32_t cond_client_flags = 0;
3962 u_int8_t cond_local_networks_flags = 0;
3963 u_int32_t offset = 0;
3964 u_int8_t ultimate_result = 0;
3965 u_int32_t secondary_result = 0;
3966 struct necp_policy_condition_agent_type cond_agent_type = {};
3967 struct necp_policy_condition_sdk_version cond_sdk_version = {};
3968 u_int16_t cond_packet_filter_tags = 0;
3969 u_int16_t cond_scheme_port = 0;
3970 u_int32_t cond_bound_interface_flags = 0;
3971 u_int32_t cond_bound_interface_eflags = 0;
3972 u_int32_t cond_bound_interface_xflags = 0;
3973 necp_kernel_policy_result_parameter secondary_result_parameter;
3974 memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
3975 u_int32_t cond_last_interface_index = 0;
3976 necp_kernel_policy_result_parameter ultimate_result_parameter;
3977 memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
3978
3979 if (policy == NULL) {
3980 return FALSE;
3981 }
3982
3983 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3984
3985 // Process conditions
3986 while (offset < policy->conditions_size) {
3987 u_int32_t length = 0;
3988 u_int8_t * __indexable value = necp_buffer_get_tlv_value(policy->conditions, policy->conditions_size, offset, &length);
3989
3990 u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
3991 u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
3992 bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
3993 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
3994 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
3995 switch (condition_type) {
3996 case NECP_POLICY_CONDITION_DEFAULT: {
3997 socket_ip_conditions = TRUE;
3998 break;
3999 }
4000 case NECP_POLICY_CONDITION_ALL_INTERFACES: {
4001 master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
4002 socket_ip_conditions = TRUE;
4003 break;
4004 }
4005 case NECP_POLICY_CONDITION_HAS_CLIENT: {
4006 master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
4007 socket_only_conditions = TRUE;
4008 break;
4009 }
4010 case NECP_POLICY_CONDITION_ENTITLEMENT: {
4011 if (condition_length > 0) {
4012 if (cond_custom_entitlement == NULL) {
4013 cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
4014 if (cond_custom_entitlement != NULL) {
4015 master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
4016 socket_only_conditions = TRUE;
4017 }
4018 }
4019 } else {
4020 master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
4021 socket_only_conditions = TRUE;
4022 }
4023 break;
4024 }
4025 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
4026 master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4027 if (condition_is_negative) {
4028 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4029 }
4030 socket_only_conditions = TRUE;
4031 break;
4032 }
4033 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
4034 master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
4035 socket_only_conditions = TRUE;
4036 break;
4037 }
4038 case NECP_POLICY_CONDITION_SDK_VERSION: {
4039 if (condition_length >= sizeof(cond_sdk_version)) {
4040 master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
4041 memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
4042 socket_only_conditions = TRUE;
4043 }
4044 break;
4045 }
4046 case NECP_POLICY_CONDITION_DOMAIN: {
4047 // Make sure there is only one such rule
4048 if (condition_length > 0 && cond_domain == NULL) {
4049 const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
4050
4051 u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
4052 cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
4053 if (cond_domain != NULL) {
4054 master_condition_mask |= mask_value;
4055 if (condition_is_negative) {
4056 master_condition_negated_mask |= mask_value;
4057 }
4058 socket_only_conditions = TRUE;
4059 }
4060 }
4061 break;
4062 }
4063 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
4064 // Make sure there is only one such rule
4065 if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
4066 memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
4067 if (cond_domain_filter != 0) {
4068 master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4069 if (condition_is_negative) {
4070 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4071 }
4072 socket_only_conditions = TRUE;
4073 }
4074 }
4075 break;
4076 }
4077 case NECP_POLICY_CONDITION_URL: {
4078 // Make sure there is only one such rule
4079 if (condition_length > 0 && cond_url == NULL) {
4080 u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
4081 cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
4082 if (cond_url != NULL) {
4083 master_condition_mask |= mask_value;
4084 if (condition_is_negative) {
4085 master_condition_negated_mask |= mask_value;
4086 }
4087 socket_only_conditions = TRUE;
4088 }
4089 }
4090 break;
4091 }
4092 case NECP_POLICY_CONDITION_ACCOUNT: {
4093 // Make sure there is only one such rule
4094 if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
4095 size_t string_buffer_size = 0;
4096 char * __sized_by(string_buffer_size) string = NULL;
4097 string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
4098 string_buffer_size = condition_length + 1;
4099 if (string != NULL) {
4100 memcpy(string, condition_value, condition_length);
4101 string[condition_length] = 0;
4102 cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(string, &string[condition_length]));
4103 if (cond_account_id != 0) {
4104 policy->applied_account = string; // Save the string in parent policy
4105 policy->applied_account_size = string_buffer_size;
4106 master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4107 if (condition_is_negative) {
4108 master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4109 }
4110 socket_only_conditions = TRUE;
4111 } else {
4112 kfree_data_sized_by(string, string_buffer_size);
4113 }
4114 }
4115 }
4116 break;
4117 }
4118 case NECP_POLICY_CONDITION_APPLICATION: {
4119 // Make sure there is only one such rule, because we save the uuid in the policy
4120 if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
4121 bool allocated_mapping = FALSE;
4122 uuid_t application_uuid;
4123 memcpy(application_uuid, condition_value, sizeof(uuid_t));
4124 cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
4125 if (cond_app_id != 0) {
4126 if (allocated_mapping) {
4127 necp_uuid_app_id_mappings_dirty = TRUE;
4128 necp_num_uuid_app_id_mappings++;
4129 }
4130 uuid_copy(policy->applied_app_uuid, application_uuid);
4131 master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
4132 if (condition_is_negative) {
4133 master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
4134 }
4135 socket_only_conditions = TRUE;
4136 }
4137 }
4138 break;
4139 }
4140 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
4141 // Make sure there is only one such rule, because we save the uuid in the policy
4142 if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
4143 uuid_t real_application_uuid;
4144 memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
4145 cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
4146 if (cond_real_app_id != 0) {
4147 uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
4148 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4149 if (condition_is_negative) {
4150 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4151 }
4152 socket_only_conditions = TRUE;
4153 }
4154 }
4155 break;
4156 }
4157 case NECP_POLICY_CONDITION_PID: {
4158 if (condition_length >= sizeof(pid_t)) {
4159 master_condition_mask |= NECP_KERNEL_CONDITION_PID;
4160 if (condition_is_negative) {
4161 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
4162 }
4163 memcpy(&cond_pid, condition_value, sizeof(cond_pid));
4164 if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
4165 memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
4166 }
4167 socket_only_conditions = TRUE;
4168 }
4169 break;
4170 }
4171 case NECP_POLICY_CONDITION_UID: {
4172 if (condition_length >= sizeof(uid_t)) {
4173 master_condition_mask |= NECP_KERNEL_CONDITION_UID;
4174 if (condition_is_negative) {
4175 master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
4176 }
4177 memcpy(&cond_uid, condition_value, sizeof(cond_uid));
4178 socket_only_conditions = TRUE;
4179 }
4180 break;
4181 }
4182 case NECP_POLICY_CONDITION_REAL_UID: {
4183 if (condition_length >= sizeof(uid_t)) {
4184 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4185 if (condition_is_negative) {
4186 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4187 }
4188 memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
4189 socket_only_conditions = TRUE;
4190 }
4191 break;
4192 }
4193 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
4194 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
4195 master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4196 if (condition_is_negative) {
4197 master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4198 }
4199 memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
4200 socket_only_conditions = TRUE;
4201 }
4202 break;
4203 }
4204 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4205 if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4206 char interface_name[IFXNAMSIZ];
4207 memcpy(interface_name, condition_value, condition_length);
4208 interface_name[condition_length - 1] = 0; // Make sure the string is NULL terminated
4209 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[condition_length - 1]), &cond_bound_interface) == 0) {
4210 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4211 if (condition_is_negative) {
4212 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4213 }
4214 }
4215 socket_ip_conditions = TRUE;
4216 }
4217 break;
4218 }
4219 case NECP_POLICY_CONDITION_IP_PROTOCOL:
4220 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4221 if (condition_length >= sizeof(u_int16_t)) {
4222 master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4223 if (condition_is_negative) {
4224 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4225 }
4226 memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4227 if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4228 socket_only_conditions = TRUE;
4229 } else {
4230 socket_ip_conditions = TRUE;
4231 }
4232 }
4233 break;
4234 }
4235 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4236 if (condition_is_negative) {
4237 master_condition_negated_mask |= NECP_POLICY_CONDITION_LOCAL_NETWORKS;
4238 }
4239 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4240 socket_ip_conditions = TRUE;
4241 if (condition_length >= sizeof(u_int8_t)) {
4242 memcpy(&cond_local_networks_flags, condition_value, sizeof(cond_local_networks_flags));
4243 }
4244 break;
4245 }
4246 case NECP_POLICY_CONDITION_LOCAL_ADDR:
4247 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4248 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4249 if (!necp_address_is_valid(&address_struct->address.sa)) {
4250 break;
4251 }
4252
4253 cond_local_prefix = address_struct->prefix;
4254 memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4255 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4256 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4257 if (condition_is_negative) {
4258 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4259 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4260 }
4261 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4262 socket_only_conditions = TRUE;
4263 } else {
4264 socket_ip_conditions = TRUE;
4265 }
4266 break;
4267 }
4268 case NECP_POLICY_CONDITION_REMOTE_ADDR:
4269 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4270 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4271 if (!necp_address_is_valid(&address_struct->address.sa)) {
4272 break;
4273 }
4274
4275 cond_remote_prefix = address_struct->prefix;
4276 memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4277 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4278 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4279 if (condition_is_negative) {
4280 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4281 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4282 }
4283 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4284 socket_only_conditions = TRUE;
4285 } else {
4286 socket_ip_conditions = TRUE;
4287 }
4288 break;
4289 }
4290 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4291 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4292 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4293 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4294 !necp_address_is_valid(&address_struct->end_address.sa)) {
4295 break;
4296 }
4297
4298 memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4299 memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4300 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4301 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4302 if (condition_is_negative) {
4303 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4304 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4305 }
4306 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4307 socket_only_conditions = TRUE;
4308 } else {
4309 socket_ip_conditions = TRUE;
4310 }
4311 break;
4312 }
4313 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4314 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4315 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4316 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4317 !necp_address_is_valid(&address_struct->end_address.sa)) {
4318 break;
4319 }
4320
4321 memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4322 memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4323 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4324 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4325 if (condition_is_negative) {
4326 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4327 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4328 }
4329 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4330 socket_only_conditions = TRUE;
4331 } else {
4332 socket_ip_conditions = TRUE;
4333 }
4334 break;
4335 }
4336 case NECP_POLICY_CONDITION_AGENT_TYPE: {
4337 if (condition_length >= sizeof(cond_agent_type)) {
4338 master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4339 memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4340 socket_only_conditions = TRUE;
4341 }
4342 break;
4343 }
4344 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4345 if (condition_is_negative) {
4346 master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4347 }
4348 master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4349 socket_only_conditions = TRUE;
4350 if (condition_length >= sizeof(u_int32_t)) {
4351 memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4352 } else {
4353 // Empty means match on fallback traffic
4354 cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4355 }
4356 break;
4357 }
4358 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4359 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4360 if (condition_is_negative) {
4361 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4362 }
4363 socket_only_conditions = TRUE;
4364 break;
4365 }
4366 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4367 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4368 if (condition_is_negative) {
4369 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4370 }
4371 socket_only_conditions = TRUE;
4372 break;
4373 }
4374 case NECP_POLICY_CONDITION_SCHEME_PORT: {
4375 master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4376 if (condition_is_negative) {
4377 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4378 }
4379 memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4380 socket_ip_conditions = TRUE;
4381 break;
4382 }
4383 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4384 if (condition_length > 0) {
4385 if (cond_signing_identifier == NULL) {
4386 cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4387 if (cond_signing_identifier != NULL) {
4388 master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4389 socket_only_conditions = TRUE;
4390 if (condition_is_negative) {
4391 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4392 }
4393 }
4394 }
4395 }
4396 break;
4397 }
4398 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4399 if (condition_length >= sizeof(u_int16_t)) {
4400 master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4401 if (condition_is_negative) {
4402 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4403 }
4404 memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4405 socket_ip_conditions = TRUE;
4406 }
4407 break;
4408 }
4409 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4410 master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4411 if (condition_is_negative) {
4412 master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4413 }
4414 socket_only_conditions = TRUE;
4415 break;
4416 }
4417 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4418 master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4419 if (condition_is_negative) {
4420 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4421 }
4422 socket_only_conditions = TRUE;
4423 break;
4424 }
4425 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4426 if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4427 u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4428 memcpy(&flags, condition_value, sizeof(flags));
4429 cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4430 cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4431 cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4432 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4433 if (condition_is_negative) {
4434 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4435 }
4436 socket_ip_conditions = TRUE;
4437 }
4438 break;
4439 }
4440 default: {
4441 break;
4442 }
4443 }
4444
4445 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4446 }
4447
4448 // Process result
4449 ultimate_result = necp_policy_get_result_type(policy);
4450 switch (ultimate_result) {
4451 case NECP_POLICY_RESULT_PASS: {
4452 u_int32_t pass_flags = 0;
4453 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4454 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4455 ultimate_result_parameter.pass_flags = pass_flags;
4456 }
4457 }
4458 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4459 socket_layer_non_id_conditions = TRUE;
4460 ip_output_layer_id_condition = TRUE;
4461 } else if (socket_ip_conditions) {
4462 socket_layer_non_id_conditions = TRUE;
4463 ip_output_layer_id_condition = TRUE;
4464 ip_output_layer_non_id_conditions = TRUE;
4465 }
4466 break;
4467 }
4468 case NECP_POLICY_RESULT_DROP: {
4469 u_int32_t drop_flags = 0;
4470 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4471 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4472 ultimate_result_parameter.drop_flags = drop_flags;
4473 }
4474 }
4475 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4476 socket_layer_non_id_conditions = TRUE;
4477 } else if (socket_ip_conditions) {
4478 socket_layer_non_id_conditions = TRUE;
4479 ip_output_layer_non_id_conditions = TRUE;
4480 ip_output_layer_non_id_only = TRUE; // Only apply drop to packets that didn't go through socket layer
4481 }
4482 break;
4483 }
4484 case NECP_POLICY_RESULT_SKIP: {
4485 u_int32_t skip_policy_order = 0;
4486 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4487 ultimate_result_parameter.skip_policy_order = skip_policy_order;
4488 }
4489
4490 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4491 socket_layer_non_id_conditions = TRUE;
4492 ip_output_layer_id_condition = TRUE;
4493 } else if (socket_ip_conditions) {
4494 socket_layer_non_id_conditions = TRUE;
4495 ip_output_layer_non_id_conditions = TRUE;
4496 }
4497 break;
4498 }
4499 case NECP_POLICY_RESULT_SOCKET_DIVERT:
4500 case NECP_POLICY_RESULT_SOCKET_FILTER: {
4501 u_int32_t control_unit = 0;
4502 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4503 ultimate_result_parameter.flow_divert_control_unit = control_unit;
4504 }
4505 socket_layer_non_id_conditions = TRUE;
4506 break;
4507 }
4508 case NECP_POLICY_RESULT_IP_TUNNEL: {
4509 struct necp_policy_result_ip_tunnel tunnel_parameters;
4510 u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4511 if (tunnel_parameters_length > sizeof(u_int32_t) &&
4512 tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4513 necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4514 ifnet_t __single tunnel_interface = NULL;
4515 tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0; // Make sure the string is NULL terminated
4516 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4517 ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4518 ifnet_release(tunnel_interface);
4519 }
4520
4521 secondary_result = tunnel_parameters.secondary_result;
4522 if (secondary_result) {
4523 cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4524 }
4525 }
4526
4527 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4528 socket_layer_non_id_conditions = TRUE;
4529 ip_output_layer_id_condition = TRUE;
4530 if (secondary_result) {
4531 ip_output_layer_tunnel_condition_from_id = TRUE;
4532 }
4533 } else if (socket_ip_conditions) {
4534 socket_layer_non_id_conditions = TRUE;
4535 ip_output_layer_id_condition = TRUE;
4536 ip_output_layer_non_id_conditions = TRUE;
4537 if (secondary_result) {
4538 ip_output_layer_tunnel_condition_from_id = TRUE;
4539 ip_output_layer_tunnel_condition_from_non_id = TRUE;
4540 }
4541 }
4542 break;
4543 }
4544 case NECP_POLICY_RESULT_USE_NETAGENT:
4545 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4546 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4547 uuid_t netagent_uuid;
4548 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4549 ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
4550 if (ultimate_result_parameter.netagent_id != 0) {
4551 uuid_copy(policy->applied_result_uuid, netagent_uuid);
4552 socket_layer_non_id_conditions = TRUE;
4553 }
4554 }
4555 break;
4556 }
4557 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4558 u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4559 if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4560 char interface_name[IFXNAMSIZ];
4561 ifnet_t __single scope_interface = NULL;
4562 necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4563 interface_name[interface_name_length - 1] = 0; // Make sure the string is NULL terminated
4564 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4565 ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4566 socket_layer_non_id_conditions = TRUE;
4567 ifnet_release(scope_interface);
4568 }
4569 }
4570 break;
4571 }
4572 case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4573 socket_layer_non_id_conditions = TRUE;
4574 break;
4575 }
4576 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4577 socket_layer_non_id_conditions = TRUE;
4578 break;
4579 }
4580 case NECP_POLICY_RESULT_ROUTE_RULES: {
4581 if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4582 bool has_socket_only_actions = FALSE;
4583 u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4584 if (route_rule_id > 0) {
4585 policy->applied_route_rules_id = route_rule_id;
4586 ultimate_result_parameter.route_rule_id = route_rule_id;
4587 if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4588 socket_layer_non_id_conditions = TRUE;
4589 } else if (socket_ip_conditions) {
4590 socket_layer_non_id_conditions = TRUE;
4591 ip_output_layer_non_id_conditions = TRUE;
4592 ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4593 }
4594 }
4595 }
4596 break;
4597 }
4598 default: {
4599 break;
4600 }
4601 }
4602
4603 if (socket_layer_non_id_conditions) {
4604 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);
4605
4606 if (policy_id == 0) {
4607 NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4608 goto fail;
4609 }
4610
4611 cond_ip_output_layer_id = policy_id;
4612 policy->kernel_socket_policies[0] = policy_id;
4613 }
4614
4615 if (ip_output_layer_non_id_conditions) {
4616 u_int64_t condition_mask = master_condition_mask;
4617 if (ip_output_layer_non_id_only) {
4618 condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4619 }
4620
4621 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);
4622
4623 if (policy_id == 0) {
4624 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4625 goto fail;
4626 }
4627
4628 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4629 }
4630
4631 if (ip_output_layer_id_condition) {
4632 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);
4633
4634 if (policy_id == 0) {
4635 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4636 goto fail;
4637 }
4638
4639 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4640 }
4641
4642 // Extra policies for IP Output tunnels for when packets loop back
4643 if (ip_output_layer_tunnel_condition_from_id) {
4644 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);
4645
4646 if (policy_id == 0) {
4647 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4648 goto fail;
4649 }
4650
4651 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4652 }
4653
4654 if (ip_output_layer_tunnel_condition_from_id) {
4655 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);
4656
4657 if (policy_id == 0) {
4658 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4659 goto fail;
4660 }
4661
4662 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4663 }
4664
4665 policy->applied = TRUE;
4666 policy->pending_update = FALSE;
4667 return TRUE;
4668
4669 fail:
4670 return FALSE;
4671 }
4672
4673 static void
necp_policy_apply_all(struct necp_session * session)4674 necp_policy_apply_all(struct necp_session *session)
4675 {
4676 struct necp_session_policy *policy = NULL;
4677 struct necp_session_policy *temp_policy = NULL;
4678 struct kev_necp_policies_changed_data kev_data;
4679 kev_data.changed_count = 0;
4680
4681 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4682
4683 // Remove exisiting applied policies
4684 if (session->dirty) {
4685 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4686 if (policy->pending_deletion) {
4687 if (policy->applied) {
4688 necp_policy_unapply(policy);
4689 }
4690 // Delete the policy
4691 necp_policy_delete(session, policy);
4692 } else if (!policy->applied) {
4693 necp_policy_apply(session, policy);
4694 } else if (policy->pending_update) {
4695 // Must have been applied, but needs an update. Remove and re-add.
4696 necp_policy_unapply(policy);
4697 necp_policy_apply(session, policy);
4698 }
4699 }
4700
4701 necp_kernel_socket_policies_update_uuid_table();
4702 necp_kernel_socket_policies_reprocess();
4703 necp_kernel_ip_output_policies_reprocess();
4704
4705 // Clear dirty bit flags
4706 session->dirty = FALSE;
4707 }
4708
4709 lck_rw_done(&necp_kernel_policy_lock);
4710
4711 necp_update_all_clients();
4712 necp_post_change_event(&kev_data);
4713
4714 if (necp_debug) {
4715 NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4716 }
4717 }
4718
4719 // Kernel Policy Management
4720 // ---------------------
4721 // Kernel policies are derived from session policies
4722 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4723 necp_kernel_policy_get_new_id(bool socket_level)
4724 {
4725 static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4726 static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4727
4728 necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4729
4730 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4731
4732 if (socket_level) {
4733 bool wrapped = FALSE;
4734 do {
4735 necp_last_kernel_socket_policy_id++;
4736 if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4737 necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4738 if (wrapped) {
4739 // Already wrapped, give up
4740 NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4741 return NECP_KERNEL_POLICY_ID_NONE;
4742 }
4743 necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4744 wrapped = TRUE;
4745 }
4746 newid = necp_last_kernel_socket_policy_id;
4747 } while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4748 } else {
4749 bool wrapped = FALSE;
4750 do {
4751 necp_last_kernel_ip_policy_id++;
4752 if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4753 if (wrapped) {
4754 // Already wrapped, give up
4755 NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4756 return NECP_KERNEL_POLICY_ID_NONE;
4757 }
4758 necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4759 wrapped = TRUE;
4760 }
4761 newid = necp_last_kernel_ip_policy_id;
4762 } while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4763 }
4764
4765 if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4766 NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4767 return NECP_KERNEL_POLICY_ID_NONE;
4768 }
4769
4770 return newid;
4771 }
4772
4773 #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)
4774
4775 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)4776 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)
4777 {
4778 struct necp_kernel_socket_policy *new_kernel_policy = NULL;
4779 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4780
4781 new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
4782
4783 new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
4784 new_kernel_policy->order = order;
4785 new_kernel_policy->session_order = session_order;
4786 new_kernel_policy->session_pid = session_pid;
4787
4788 // Sanitize condition mask
4789 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
4790 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
4791 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4792 }
4793 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
4794 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4795 }
4796 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
4797 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
4798 }
4799 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
4800 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4801 }
4802 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
4803 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4804 }
4805 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
4806 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
4807 }
4808 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
4809 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
4810 }
4811 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
4812
4813 // Set condition values
4814 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4815 new_kernel_policy->cond_app_id = cond_app_id;
4816 }
4817 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4818 new_kernel_policy->cond_real_app_id = cond_real_app_id;
4819 }
4820 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
4821 new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
4822 }
4823 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4824 new_kernel_policy->cond_account_id = cond_account_id;
4825 }
4826 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
4827 (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
4828 new_kernel_policy->cond_domain = cond_domain;
4829 new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
4830 }
4831 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
4832 new_kernel_policy->cond_domain_filter = cond_domain_filter;
4833 }
4834 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
4835 new_kernel_policy->cond_url = cond_url;
4836 }
4837 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
4838 new_kernel_policy->cond_pid = cond_pid;
4839 new_kernel_policy->cond_pid_version = cond_pid_version;
4840 }
4841 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
4842 new_kernel_policy->cond_uid = cond_uid;
4843 }
4844 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
4845 new_kernel_policy->cond_real_uid = cond_real_uid;
4846 }
4847 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
4848 if (cond_bound_interface) {
4849 ifnet_reference(cond_bound_interface);
4850 }
4851 new_kernel_policy->cond_bound_interface = cond_bound_interface;
4852 }
4853 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4854 new_kernel_policy->cond_traffic_class = cond_traffic_class;
4855 }
4856 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4857 new_kernel_policy->cond_protocol = cond_protocol;
4858 }
4859 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4860 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
4861 }
4862 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4863 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
4864 }
4865 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4866 new_kernel_policy->cond_local_prefix = cond_local_prefix;
4867 }
4868 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4869 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
4870 }
4871 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4872 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
4873 }
4874 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4875 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
4876 }
4877 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
4878 memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
4879 }
4880 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
4881 memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
4882 }
4883 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
4884 new_kernel_policy->cond_client_flags = cond_client_flags;
4885 }
4886 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
4887 new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
4888 }
4889 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
4890 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
4891 }
4892 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
4893 new_kernel_policy->cond_scheme_port = cond_scheme_port;
4894 }
4895 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
4896 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
4897 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
4898 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
4899 }
4900 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
4901 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
4902 }
4903
4904 new_kernel_policy->result = result;
4905 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
4906
4907 if (necp_debug) {
4908 NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
4909 }
4910 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
4911
4912 return new_kernel_policy ? new_kernel_policy->id : 0;
4913 }
4914
4915 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)4916 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
4917 {
4918 struct necp_kernel_socket_policy *kernel_policy = NULL;
4919 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4920
4921 if (policy_id == 0) {
4922 return NULL;
4923 }
4924
4925 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
4926 if (kernel_policy->id == policy_id) {
4927 return kernel_policy;
4928 }
4929 }
4930
4931 return NULL;
4932 }
4933
4934 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)4935 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
4936 {
4937 struct necp_kernel_socket_policy * __single policy = NULL;
4938 char * __indexable buffer = NULL;
4939 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4940
4941 policy = necp_kernel_socket_policy_find(policy_id);
4942 if (policy) {
4943 LIST_REMOVE(policy, chain);
4944
4945 if (policy->cond_bound_interface) {
4946 ifnet_release(policy->cond_bound_interface);
4947 policy->cond_bound_interface = NULL;
4948 }
4949
4950 if (policy->cond_domain) {
4951 buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
4952 kfree_data_addr(buffer);
4953 policy->cond_domain = NULL;
4954 }
4955
4956 if (policy->cond_url) {
4957 buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
4958 kfree_data_addr(buffer);
4959 policy->cond_url = NULL;
4960 }
4961
4962 if (policy->cond_custom_entitlement) {
4963 buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
4964 kfree_data_addr(buffer);
4965 policy->cond_custom_entitlement = NULL;
4966 }
4967
4968 if (policy->cond_signing_identifier) {
4969 buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
4970 kfree_data_addr(buffer);
4971 policy->cond_signing_identifier = NULL;
4972 }
4973
4974 zfree(necp_socket_policy_zone, policy);
4975 return TRUE;
4976 }
4977
4978 return FALSE;
4979 }
4980
4981 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)4982 __sized_by(MAX_RESULT_STRING_LEN)
4983 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)
4984 {
4985 uuid_string_t uuid_string;
4986 switch (result) {
4987 case NECP_KERNEL_POLICY_RESULT_NONE: {
4988 snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
4989 break;
4990 }
4991 case NECP_KERNEL_POLICY_RESULT_PASS: {
4992 snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
4993 break;
4994 }
4995 case NECP_KERNEL_POLICY_RESULT_SKIP: {
4996 snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
4997 break;
4998 }
4999 case NECP_KERNEL_POLICY_RESULT_DROP: {
5000 snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5001 break;
5002 }
5003 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5004 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5005 break;
5006 }
5007 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5008 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5009 break;
5010 }
5011 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5012 ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5013 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5014 break;
5015 }
5016 case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5017 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5018 break;
5019 }
5020 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5021 ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5022 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5023 break;
5024 }
5025 case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5026 snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5027 break;
5028 }
5029 case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5030 snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5031 break;
5032 }
5033 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5034 int index = 0;
5035 char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5036 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5037 if (route_rule != NULL) {
5038 for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5039 if (route_rule->exception_if_indices[index] != 0) {
5040 ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5041 snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5042 } else {
5043 memset(interface_names[index], 0, IFXNAMSIZ);
5044 }
5045 }
5046 switch (route_rule->default_action) {
5047 case NECP_ROUTE_RULE_DENY_INTERFACE:
5048 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5049 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)",
5050 (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5051 (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5052 (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5053 (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5054 (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5055 (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5056 (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5057 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5058 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5059 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5060 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5061 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5062 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5063 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5064 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5065 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5066 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5067 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5068 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5069 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5070 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5071 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5072 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5073 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5074 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5075 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5076 break;
5077 case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5078 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)",
5079 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5080 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5081 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5082 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5083 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5084 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5085 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5086 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5087 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5088 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5089 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5090 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5091 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5092 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5093 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5094 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5095 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5096 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5097 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5098 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5099 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5100 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5101 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5102 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5103 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5104 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5105 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5106 break;
5107 case NECP_ROUTE_RULE_QOS_MARKING:
5108 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)",
5109 (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5110 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5111 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5112 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5113 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5114 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5115 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5116 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5117 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5118 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5119 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5120 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5121 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5122 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5123 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5124 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5125 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5126 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5127 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5128 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5129 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5130 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5131 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5132 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5133 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5134 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5135 break;
5136 default:
5137 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5138 break;
5139 }
5140 }
5141 break;
5142 }
5143 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5144 bool found_mapping = FALSE;
5145 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5146 if (mapping != NULL) {
5147 uuid_unparse(mapping->uuid, uuid_string);
5148 found_mapping = TRUE;
5149 }
5150 snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5151 break;
5152 }
5153 case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5154 bool found_mapping = FALSE;
5155 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5156 if (mapping != NULL) {
5157 uuid_unparse(mapping->uuid, uuid_string);
5158 found_mapping = TRUE;
5159 }
5160 snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5161 break;
5162 }
5163 case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5164 bool found_mapping = FALSE;
5165 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5166 if (mapping != NULL) {
5167 uuid_unparse(mapping->uuid, uuid_string);
5168 found_mapping = TRUE;
5169 }
5170 snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5171 break;
5172 }
5173 default: {
5174 snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5175 break;
5176 }
5177 }
5178 return result_string;
5179 }
5180
5181 static void
necp_kernel_socket_policies_dump_all(void)5182 necp_kernel_socket_policies_dump_all(void)
5183 {
5184 if (necp_debug) {
5185 struct necp_kernel_socket_policy *policy = NULL;
5186 int policy_i;
5187 int app_i;
5188 char result_string[MAX_RESULT_STRING_LEN];
5189 char proc_name_string[MAXCOMLEN + 1];
5190 memset(result_string, 0, MAX_RESULT_STRING_LEN);
5191 memset(proc_name_string, 0, MAXCOMLEN + 1);
5192
5193 NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5194 NECPLOG0(LOG_DEBUG, "-----------\n");
5195 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5196 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5197 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5198 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));
5199 }
5200 if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5201 NECPLOG0(LOG_DEBUG, "-----------\n");
5202 }
5203
5204 NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5205 NECPLOG0(LOG_DEBUG, "-----------\n");
5206 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5207 NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5208 for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5209 policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5210 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5211 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));
5212 }
5213 NECPLOG0(LOG_DEBUG, "-----------\n");
5214 }
5215 }
5216 }
5217
5218 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5219 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5220 {
5221 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5222 // Drop always cancels out lower policies
5223 return TRUE;
5224 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5225 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5226 upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5227 upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5228 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5229 upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
5230 // Filters and route rules never cancel out lower policies
5231 return FALSE;
5232 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5233 if (upper_policy->session_order != lower_policy->session_order) {
5234 // A skip cannot override a policy of a different session
5235 return FALSE;
5236 } else {
5237 if (upper_policy->result_parameter.skip_policy_order == 0 ||
5238 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5239 // This policy is beyond the skip
5240 return FALSE;
5241 } else {
5242 // This policy is inside the skip
5243 return TRUE;
5244 }
5245 }
5246 }
5247
5248 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5249 return TRUE;
5250 }
5251
5252 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)5253 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5254 {
5255 bool can_skip = FALSE;
5256 u_int32_t highest_skip_session_order = 0;
5257 u_int32_t highest_skip_order = 0;
5258 int i;
5259 for (i = 0; i < valid_indices; i++) {
5260 struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5261
5262 // For policies in a skip window, we can't mark conflicting policies as unnecessary
5263 if (can_skip) {
5264 if (highest_skip_session_order != compared_policy->session_order ||
5265 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5266 // If we've moved on to the next session, or passed the skip window
5267 highest_skip_session_order = 0;
5268 highest_skip_order = 0;
5269 can_skip = FALSE;
5270 } else {
5271 // If this policy is also a skip, in can increase the skip window
5272 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5273 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5274 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5275 }
5276 }
5277 continue;
5278 }
5279 }
5280
5281 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5282 // This policy is a skip. Set the skip window accordingly
5283 can_skip = TRUE;
5284 highest_skip_session_order = compared_policy->session_order;
5285 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5286 }
5287
5288 // The result of the compared policy must be able to block out this policy result
5289 if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5290 continue;
5291 }
5292
5293 // If new policy matches All Interfaces, compared policy must also
5294 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5295 continue;
5296 }
5297
5298 // If new policy matches Local Networks, compared policy must also
5299 if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5300 policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5301 continue;
5302 }
5303
5304 // Default makes lower policies unecessary always
5305 if (compared_policy->condition_mask == 0) {
5306 return TRUE;
5307 }
5308
5309 // Compared must be more general than policy, and include only conditions within policy
5310 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5311 continue;
5312 }
5313
5314 // Negative conditions must match for the overlapping conditions
5315 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5316 continue;
5317 }
5318
5319 if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5320 compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5321 strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5322 continue;
5323 }
5324
5325 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5326 compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5327 continue;
5328 }
5329
5330 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5331 strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5332 continue;
5333 }
5334
5335 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5336 strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5337 continue;
5338 }
5339
5340 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5341 compared_policy->cond_account_id != policy->cond_account_id) {
5342 continue;
5343 }
5344
5345 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5346 compared_policy->cond_policy_id != policy->cond_policy_id) {
5347 continue;
5348 }
5349
5350 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5351 compared_policy->cond_app_id != policy->cond_app_id) {
5352 continue;
5353 }
5354
5355 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5356 compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5357 continue;
5358 }
5359
5360 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5361 (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5362 continue;
5363 }
5364
5365 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5366 compared_policy->cond_uid != policy->cond_uid) {
5367 continue;
5368 }
5369
5370 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5371 compared_policy->cond_real_uid != policy->cond_real_uid) {
5372 continue;
5373 }
5374
5375 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5376 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5377 continue;
5378 }
5379
5380 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5381 compared_policy->cond_protocol != policy->cond_protocol) {
5382 continue;
5383 }
5384
5385 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5386 compared_policy->cond_client_flags != policy->cond_client_flags) {
5387 continue;
5388 }
5389
5390 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5391 !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5392 compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5393 continue;
5394 }
5395
5396 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5397 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5398 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))) {
5399 continue;
5400 }
5401 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5402 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5403 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5404 continue;
5405 }
5406 }
5407 }
5408
5409 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5410 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5411 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))) {
5412 continue;
5413 }
5414 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5415 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5416 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5417 continue;
5418 }
5419 }
5420 }
5421
5422 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5423 memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5424 continue;
5425 }
5426
5427 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5428 memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5429 continue;
5430 }
5431
5432 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5433 memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5434 continue;
5435 }
5436
5437 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5438 memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5439 continue;
5440 }
5441
5442 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5443 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5444 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5445 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5446 continue;
5447 }
5448
5449 return TRUE;
5450 }
5451
5452 return FALSE;
5453 }
5454
5455 static bool
necp_kernel_socket_policies_reprocess(void)5456 necp_kernel_socket_policies_reprocess(void)
5457 {
5458 int app_i;
5459 int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5460 int app_layer_current_free_index = 0;
5461 struct necp_kernel_socket_policy *kernel_policy = NULL;
5462
5463 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5464
5465 // Reset mask to 0
5466 necp_kernel_application_policies_condition_mask = 0;
5467 necp_kernel_socket_policies_condition_mask = 0;
5468 necp_kernel_application_policies_count = 0;
5469 necp_kernel_socket_policies_count = 0;
5470 necp_kernel_socket_policies_non_app_count = 0;
5471
5472 // Reset all maps to NULL
5473 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5474 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5475 kfree_type(struct necp_kernel_socket_policy *,
5476 necp_kernel_socket_policies_map_counts[app_i] + 1,
5477 necp_kernel_socket_policies_map[app_i]);
5478 necp_kernel_socket_policies_map[app_i] = NULL;
5479 }
5480
5481 // Init counts
5482 necp_kernel_socket_policies_map_counts[app_i] = 0;
5483 }
5484 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5485 kfree_type(struct necp_kernel_socket_policy *,
5486 necp_kernel_socket_policies_app_layer_map_count + 1,
5487 necp_kernel_socket_policies_app_layer_map);
5488 }
5489 necp_kernel_socket_policies_app_layer_map = NULL;
5490 necp_kernel_socket_policies_app_layer_map_count = 0;
5491
5492 // Create masks and counts
5493 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5494 // App layer mask/count
5495 necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5496 necp_kernel_application_policies_count++;
5497 necp_kernel_socket_policies_app_layer_map_count++;
5498
5499 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5500 // Agent type conditions only apply to app layer
5501 continue;
5502 }
5503
5504 // Update socket layer bucket mask/counts
5505 necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5506 necp_kernel_socket_policies_count++;
5507
5508 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5509 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5510 necp_kernel_socket_policies_non_app_count++;
5511 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5512 necp_kernel_socket_policies_map_counts[app_i]++;
5513 }
5514 } else {
5515 necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5516 }
5517 }
5518
5519 // Allocate maps
5520 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5521 if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5522 // Allocate a NULL-terminated array of policy pointers for each bucket
5523 necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5524 necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5525 if (necp_kernel_socket_policies_map[app_i] == NULL) {
5526 goto fail;
5527 }
5528 }
5529 bucket_current_free_index[app_i] = 0;
5530 }
5531 necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5532 necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5533 if (necp_kernel_socket_policies_app_layer_map == NULL) {
5534 goto fail;
5535 }
5536
5537 // Fill out maps
5538 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5539 // Add app layer policies
5540 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5541 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5542 app_layer_current_free_index++;
5543 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5544 }
5545
5546 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5547 // Agent type conditions only apply to app layer
5548 continue;
5549 }
5550
5551 // Add socket policies
5552 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5553 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5554 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5555 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])) {
5556 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5557 bucket_current_free_index[app_i]++;
5558 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5559 }
5560 }
5561 } else {
5562 app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5563 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])) {
5564 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5565 bucket_current_free_index[app_i]++;
5566 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5567 }
5568 }
5569 }
5570 necp_kernel_socket_policies_dump_all();
5571 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5572 return TRUE;
5573
5574 fail:
5575 // Free memory, reset masks to 0
5576 necp_kernel_application_policies_condition_mask = 0;
5577 necp_kernel_socket_policies_condition_mask = 0;
5578 necp_kernel_application_policies_count = 0;
5579 necp_kernel_socket_policies_count = 0;
5580 necp_kernel_socket_policies_non_app_count = 0;
5581 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5582 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5583 kfree_type(struct necp_kernel_socket_policy *,
5584 necp_kernel_socket_policies_map_counts[app_i] + 1,
5585 necp_kernel_socket_policies_map[app_i]);
5586 necp_kernel_socket_policies_map[app_i] = NULL;
5587 }
5588 necp_kernel_socket_policies_map_counts[app_i] = 0;
5589 }
5590 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5591 kfree_type(struct necp_kernel_socket_policy *,
5592 necp_kernel_socket_policies_app_layer_map_count + 1,
5593 necp_kernel_socket_policies_app_layer_map);
5594 necp_kernel_socket_policies_app_layer_map = NULL;
5595 }
5596 necp_kernel_socket_policies_app_layer_map_count = 0;
5597 return FALSE;
5598 }
5599
5600 static u_int32_t
necp_get_new_string_id(void)5601 necp_get_new_string_id(void)
5602 {
5603 static u_int32_t necp_last_string_id = 0;
5604
5605 u_int32_t newid = 0;
5606
5607 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5608
5609 bool wrapped = FALSE;
5610 do {
5611 necp_last_string_id++;
5612 if (necp_last_string_id < 1) {
5613 if (wrapped) {
5614 // Already wrapped, give up
5615 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5616 return 0;
5617 }
5618 necp_last_string_id = 1;
5619 wrapped = TRUE;
5620 }
5621 newid = necp_last_string_id;
5622 } while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5623
5624 if (newid == 0) {
5625 NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5626 return 0;
5627 }
5628
5629 return newid;
5630 }
5631
5632 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5633 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5634 {
5635 struct necp_string_id_mapping *searchentry = NULL;
5636 struct necp_string_id_mapping *foundentry = NULL;
5637
5638 LIST_FOREACH(searchentry, list, chain) {
5639 if (strcmp(searchentry->string, string) == 0) {
5640 foundentry = searchentry;
5641 break;
5642 }
5643 }
5644
5645 return foundentry;
5646 }
5647
5648 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5649 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5650 {
5651 struct necp_string_id_mapping *searchentry = NULL;
5652 struct necp_string_id_mapping *foundentry = NULL;
5653
5654 LIST_FOREACH(searchentry, list, chain) {
5655 if (searchentry->id == local_id) {
5656 foundentry = searchentry;
5657 break;
5658 }
5659 }
5660
5661 return foundentry;
5662 }
5663
5664 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5665 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5666 {
5667 u_int32_t string_id = 0;
5668 struct necp_string_id_mapping *existing_mapping = NULL;
5669
5670 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5671
5672 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5673 if (existing_mapping != NULL) {
5674 string_id = existing_mapping->id;
5675 os_ref_retain_locked(&existing_mapping->refcount);
5676 } else {
5677 struct necp_string_id_mapping * __single new_mapping = NULL;
5678 new_mapping = kalloc_type(struct necp_string_id_mapping,
5679 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5680
5681 size_t length = strlen(string) + 1;
5682 char *buffer = kalloc_data(length, Z_WAITOK);
5683 if (buffer != NULL) {
5684 strlcpy(buffer, string, length);
5685 new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5686 new_mapping->id = necp_get_new_string_id();
5687 os_ref_init(&new_mapping->refcount, &necp_refgrp);
5688 LIST_INSERT_HEAD(list, new_mapping, chain);
5689 string_id = new_mapping->id;
5690 } else {
5691 kfree_type(struct necp_string_id_mapping, new_mapping);
5692 new_mapping = NULL;
5693 }
5694 }
5695 return string_id;
5696 }
5697
5698 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5699 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5700 {
5701 struct necp_string_id_mapping * __single existing_mapping = NULL;
5702 char * __indexable buffer = NULL;
5703
5704 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5705
5706 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5707 if (existing_mapping != NULL) {
5708 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5709 LIST_REMOVE(existing_mapping, chain);
5710 buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5711 kfree_data_addr(buffer);
5712 kfree_type(struct necp_string_id_mapping, existing_mapping);
5713 }
5714 return TRUE;
5715 }
5716
5717 return FALSE;
5718 }
5719
5720 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5721 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5722 {
5723 struct necp_domain_filter *searchfilter = NULL;
5724 struct necp_domain_filter *foundfilter = NULL;
5725
5726 LIST_FOREACH(searchfilter, list, chain) {
5727 if (searchfilter->id == filter_id) {
5728 foundfilter = searchfilter;
5729 break;
5730 }
5731 }
5732
5733 return foundfilter;
5734 }
5735
5736 static u_int32_t
necp_get_new_domain_filter_id(void)5737 necp_get_new_domain_filter_id(void)
5738 {
5739 static u_int32_t necp_last_filter_id = 0;
5740
5741 u_int32_t newid = 0;
5742
5743 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5744
5745 bool wrapped = FALSE;
5746 do {
5747 necp_last_filter_id++;
5748 if (necp_last_filter_id < 1) {
5749 if (wrapped) {
5750 // Already wrapped, give up
5751 NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5752 return 0;
5753 }
5754 necp_last_filter_id = 1;
5755 wrapped = TRUE;
5756 }
5757 newid = necp_last_filter_id;
5758 } while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5759
5760 if (newid == 0) {
5761 NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5762 return 0;
5763 }
5764
5765 return newid;
5766 }
5767
5768 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)5769 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5770 {
5771 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5772
5773 struct necp_domain_filter *new_filter = NULL;
5774 new_filter = kalloc_type(struct necp_domain_filter,
5775 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5776
5777 new_filter->filter = filter;
5778 new_filter->id = necp_get_new_domain_filter_id();
5779 LIST_INSERT_HEAD(list, new_filter, chain);
5780 LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
5781 os_ref_init(&new_filter->refcount, &necp_refgrp);
5782
5783 return new_filter->id;
5784 }
5785
5786 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)5787 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
5788 {
5789 struct necp_domain_filter * __single existing_filter = NULL;
5790
5791 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5792
5793 existing_filter = necp_lookup_domain_filter(list, filter_id);
5794 if (existing_filter != NULL) {
5795 if (os_ref_release_locked(&existing_filter->refcount) == 0) {
5796 LIST_REMOVE(existing_filter, chain);
5797 LIST_REMOVE(existing_filter, owner_chain);
5798 net_bloom_filter_destroy(existing_filter->filter);
5799 kfree_type(struct necp_domain_filter, existing_filter);
5800 }
5801 return true;
5802 }
5803
5804 return false;
5805 }
5806
5807 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
5808 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
5809 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)5810 necp_get_new_route_rule_id(bool aggregate)
5811 {
5812 static u_int32_t necp_last_route_rule_id = 0;
5813 static u_int32_t necp_last_aggregate_route_rule_id = 0;
5814
5815 u_int32_t newid = 0;
5816
5817 if (!aggregate) {
5818 // Main necp_kernel_policy_lock protects non-aggregate rule IDs
5819 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5820
5821 bool wrapped = FALSE;
5822 do {
5823 necp_last_route_rule_id++;
5824 if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
5825 necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5826 if (wrapped) {
5827 // Already wrapped, give up
5828 NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
5829 return 0;
5830 }
5831 necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
5832 wrapped = TRUE;
5833 }
5834 newid = necp_last_route_rule_id;
5835 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
5836 } else {
5837 // necp_route_rule_lock protects aggregate rule IDs
5838 LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
5839
5840 bool wrapped = FALSE;
5841 do {
5842 necp_last_aggregate_route_rule_id++;
5843 if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5844 if (wrapped) {
5845 // Already wrapped, give up
5846 NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
5847 return 0;
5848 }
5849 necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
5850 wrapped = TRUE;
5851 }
5852 newid = necp_last_aggregate_route_rule_id;
5853 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
5854 }
5855
5856 if (newid == 0) {
5857 NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
5858 return 0;
5859 }
5860
5861 return newid;
5862 }
5863
5864 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)5865 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
5866 {
5867 struct necp_route_rule *searchentry = NULL;
5868 struct necp_route_rule *foundentry = NULL;
5869
5870 LIST_FOREACH(searchentry, list, chain) {
5871 if (searchentry->id == route_rule_id) {
5872 foundentry = searchentry;
5873 break;
5874 }
5875 }
5876
5877 return foundentry;
5878 }
5879
5880 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)5881 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)
5882 {
5883 struct necp_route_rule *searchentry = NULL;
5884 struct necp_route_rule *foundentry = NULL;
5885
5886 LIST_FOREACH(searchentry, list, chain) {
5887 if (searchentry->default_action == default_action &&
5888 searchentry->cellular_action == cellular_action &&
5889 searchentry->wifi_action == wifi_action &&
5890 searchentry->wired_action == wired_action &&
5891 searchentry->expensive_action == expensive_action &&
5892 searchentry->constrained_action == constrained_action &&
5893 searchentry->companion_action == companion_action &&
5894 searchentry->vpn_action == vpn_action &&
5895 searchentry->control_unit == control_unit &&
5896 searchentry->effective_type == effective_type) {
5897 bool match_failed = FALSE;
5898 size_t index_a = 0;
5899 size_t index_b = 0;
5900 size_t count_a = 0;
5901 size_t count_b = 0;
5902 for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
5903 bool found_index = FALSE;
5904 if (searchentry->exception_if_indices[index_a] == 0) {
5905 break;
5906 }
5907 count_a++;
5908 for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
5909 if (if_indices[index_b] == 0) {
5910 break;
5911 }
5912 if (index_b >= count_b) {
5913 count_b = index_b + 1;
5914 }
5915 if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
5916 searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
5917 found_index = TRUE;
5918 break;
5919 }
5920 }
5921 if (!found_index) {
5922 match_failed = TRUE;
5923 break;
5924 }
5925 }
5926
5927 if (match_failed || count_a != count_b) {
5928 continue;
5929 }
5930
5931 bool has_agent_a = !uuid_is_null(netagent_uuid);
5932 bool has_agent_b = (searchentry->netagent_id != 0);
5933 if (has_agent_a != has_agent_b) {
5934 continue;
5935 }
5936
5937 if (has_agent_a) {
5938 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
5939 if (mapping == NULL) {
5940 // Bad mapping, doesn't match
5941 continue;
5942 }
5943 if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
5944 // UUIDs don't match
5945 continue;
5946 }
5947 }
5948
5949 bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
5950 bool has_match_agent_b = (searchentry->match_netagent_id != 0);
5951 if (has_match_agent_a != has_match_agent_b) {
5952 continue;
5953 }
5954
5955 if (has_match_agent_a) {
5956 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->match_netagent_id);
5957 if (mapping == NULL) {
5958 // Bad mapping, doesn't match
5959 continue;
5960 }
5961 if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
5962 // UUIDs don't match
5963 continue;
5964 }
5965 }
5966
5967 // Rules match!
5968 foundentry = searchentry;
5969 break;
5970 }
5971 }
5972
5973 return foundentry;
5974 }
5975
5976 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)5977 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,
5978 bool *has_socket_only_actions)
5979 {
5980 size_t offset = 0;
5981 u_int32_t route_rule_id = 0;
5982 struct necp_route_rule *existing_rule = NULL;
5983 u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
5984 u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
5985 u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
5986 u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
5987 u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
5988 u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
5989 u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
5990 u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
5991 u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
5992 size_t num_valid_indices = 0;
5993 memset(&if_indices, 0, sizeof(if_indices));
5994 u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
5995 memset(&if_actions, 0, sizeof(if_actions));
5996
5997 uuid_t netagent_uuid = {};
5998
5999 uuid_t match_netagent_uuid = {};
6000 uint32_t control_unit = 0;
6001 uint32_t effective_type = 0;
6002
6003 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6004
6005 if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6006 return 0;
6007 }
6008
6009 // Process rules
6010 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6011 ifnet_t __single rule_interface = NULL;
6012 char interface_name[IFXNAMSIZ];
6013 u_int32_t length = 0;
6014 u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6015
6016 if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6017 // Invalid TLV goes beyond end of the rules array
6018 break;
6019 }
6020
6021 // Increment offset for the next time through the loop
6022 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6023
6024 u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6025 u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6026 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6027 u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6028
6029 if (rule_action == NECP_ROUTE_RULE_NONE) {
6030 // Don't allow an explicit rule to be None action
6031 continue;
6032 }
6033
6034 if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6035 rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6036 if (rule_length < sizeof(uuid_t)) {
6037 // Too short, skip
6038 continue;
6039 }
6040
6041 if (!uuid_is_null(netagent_uuid)) {
6042 if (uuid_compare(netagent_uuid, rule_value) != 0) {
6043 // UUIDs don't match, skip
6044 continue;
6045 }
6046 } else {
6047 // Copy out agent UUID
6048 memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6049 }
6050
6051 // Adjust remaining length
6052 rule_value += sizeof(netagent_uuid);
6053 rule_length -= sizeof(netagent_uuid);
6054 *has_socket_only_actions = true;
6055 } else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6056 if (rule_length < sizeof(control_unit)) {
6057 // Too short, skip
6058 continue;
6059 }
6060
6061 memcpy(&control_unit, rule_value, sizeof(control_unit));
6062
6063 // Adjust remaining length
6064 rule_value += sizeof(control_unit);
6065 rule_length -= sizeof(control_unit);
6066 *has_socket_only_actions = true;
6067 } else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6068 if (rule_length < sizeof(effective_type)) {
6069 // Too short, skip
6070 continue;
6071 }
6072
6073 memcpy(&effective_type, rule_value, sizeof(effective_type));
6074
6075 // Adjust remaining length
6076 rule_value += sizeof(effective_type);
6077 rule_length -= sizeof(effective_type);
6078 }
6079
6080 if (rule_length == 0) {
6081 if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6082 cellular_action = rule_action;
6083 }
6084 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6085 wifi_action = rule_action;
6086 }
6087 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6088 wired_action = rule_action;
6089 }
6090 if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6091 expensive_action = rule_action;
6092 }
6093 if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6094 constrained_action = rule_action;
6095 }
6096 if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6097 companion_action = rule_action;
6098 }
6099 if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6100 vpn_action = rule_action;
6101 }
6102 if (rule_flags == 0) {
6103 default_action = rule_action;
6104 }
6105 continue;
6106 } else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6107 if (rule_length < sizeof(uuid_t)) {
6108 // Too short, skip
6109 continue;
6110 }
6111
6112 // Store the netagent UUID to match
6113 memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6114 // If the data is exactly a UUID, this is the default action
6115 if (rule_length == sizeof(uuid_t)) {
6116 default_action = rule_action;
6117 continue;
6118 }
6119
6120 // If the data is longer than a UUID, this also includes an interface name
6121 // Adjust remaining length to make sure the interface name is picked up below
6122 rule_value += sizeof(uuid_t);
6123 rule_length -= sizeof(uuid_t);
6124 }
6125
6126 if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6127 continue;
6128 }
6129
6130 if (rule_length <= IFXNAMSIZ) {
6131 memcpy(interface_name, rule_value, rule_length);
6132 interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6133 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6134 if_actions[num_valid_indices] = rule_action;
6135 if_indices[num_valid_indices++] = rule_interface->if_index;
6136 ifnet_release(rule_interface);
6137 }
6138 }
6139 }
6140
6141 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);
6142 if (existing_rule != NULL) {
6143 route_rule_id = existing_rule->id;
6144 os_ref_retain_locked(&existing_rule->refcount);
6145 } else {
6146 struct necp_route_rule *new_rule = NULL;
6147 new_rule = kalloc_type(struct necp_route_rule,
6148 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6149 route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6150 if (!uuid_is_null(netagent_uuid)) {
6151 new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
6152 }
6153 if (!uuid_is_null(match_netagent_uuid)) {
6154 new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(match_netagent_uuid);
6155 }
6156 new_rule->effective_type = effective_type;
6157 new_rule->control_unit = control_unit;
6158 new_rule->default_action = default_action;
6159 new_rule->cellular_action = cellular_action;
6160 new_rule->wifi_action = wifi_action;
6161 new_rule->wired_action = wired_action;
6162 new_rule->expensive_action = expensive_action;
6163 new_rule->constrained_action = constrained_action;
6164 new_rule->companion_action = companion_action;
6165 new_rule->vpn_action = vpn_action;
6166 memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6167 memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6168 os_ref_init(&new_rule->refcount, &necp_refgrp);
6169 LIST_INSERT_HEAD(list, new_rule, chain);
6170 }
6171 return route_rule_id;
6172 }
6173
6174 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6175 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6176 {
6177 if (rule_id) {
6178 lck_rw_lock_exclusive(&necp_route_rule_lock);
6179
6180 struct necp_aggregate_route_rule * __single existing_rule = NULL;
6181 struct necp_aggregate_route_rule *tmp_rule = NULL;
6182
6183 LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6184 int index = 0;
6185 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6186 u_int32_t route_rule_id = existing_rule->rule_ids[index];
6187 if (route_rule_id == rule_id) {
6188 LIST_REMOVE(existing_rule, chain);
6189 kfree_type(struct necp_aggregate_route_rule, existing_rule);
6190 break;
6191 }
6192 }
6193 }
6194
6195 lck_rw_done(&necp_route_rule_lock);
6196 }
6197 }
6198
6199 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6200 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6201 {
6202 struct necp_route_rule * __single existing_rule = NULL;
6203
6204 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6205
6206 existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6207 if (existing_rule != NULL) {
6208 if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6209 necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6210 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
6211 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->match_netagent_id);
6212 LIST_REMOVE(existing_rule, chain);
6213 kfree_type(struct necp_route_rule, existing_rule);
6214 }
6215 return TRUE;
6216 }
6217
6218 return FALSE;
6219 }
6220
6221 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6222 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6223 {
6224 struct necp_aggregate_route_rule *searchentry = NULL;
6225 struct necp_aggregate_route_rule *foundentry = NULL;
6226
6227 lck_rw_lock_shared(&necp_route_rule_lock);
6228
6229 LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6230 if (searchentry->id == route_rule_id) {
6231 foundentry = searchentry;
6232 break;
6233 }
6234 }
6235
6236 lck_rw_done(&necp_route_rule_lock);
6237
6238 return foundentry;
6239 }
6240
6241 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6242 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6243 {
6244 u_int32_t aggregate_route_rule_id = 0;
6245 struct necp_aggregate_route_rule *new_rule = NULL;
6246 struct necp_aggregate_route_rule *existing_rule = NULL;
6247
6248 lck_rw_lock_exclusive(&necp_route_rule_lock);
6249
6250 // Check if the rule already exists
6251 LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6252 if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6253 lck_rw_done(&necp_route_rule_lock);
6254 return existing_rule->id;
6255 }
6256 }
6257
6258 new_rule = kalloc_type(struct necp_aggregate_route_rule,
6259 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6260 aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6261 new_rule->id = aggregate_route_rule_id;
6262 memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6263 LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6264 lck_rw_done(&necp_route_rule_lock);
6265
6266 return aggregate_route_rule_id;
6267 }
6268
6269 #define NECP_NULL_SERVICE_ID 1
6270 #define NECP_FIRST_VALID_SERVICE_ID 2
6271 #define NECP_FIRST_VALID_APP_ID UINT16_MAX
6272 static u_int32_t
necp_get_new_uuid_id(bool service)6273 necp_get_new_uuid_id(bool service)
6274 {
6275 static u_int32_t necp_last_service_uuid_id = 0;
6276 static u_int32_t necp_last_app_uuid_id = 0;
6277
6278 u_int32_t newid = 0;
6279
6280 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6281
6282 if (service) {
6283 bool wrapped = FALSE;
6284 do {
6285 necp_last_service_uuid_id++;
6286 if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
6287 necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
6288 if (wrapped) {
6289 // Already wrapped, give up
6290 NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
6291 return NECP_NULL_SERVICE_ID;
6292 }
6293 necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
6294 wrapped = TRUE;
6295 }
6296 newid = necp_last_service_uuid_id;
6297 } while (necp_uuid_lookup_uuid_with_service_id_locked(newid) != NULL); // If already used, keep trying
6298 } else {
6299 bool wrapped = FALSE;
6300 do {
6301 necp_last_app_uuid_id++;
6302 if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
6303 if (wrapped) {
6304 // Already wrapped, give up
6305 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
6306 return NECP_NULL_SERVICE_ID;
6307 }
6308 necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
6309 wrapped = TRUE;
6310 }
6311 newid = necp_last_app_uuid_id;
6312 } while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6313 }
6314
6315 if (newid == NECP_NULL_SERVICE_ID) {
6316 NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
6317 return NECP_NULL_SERVICE_ID;
6318 }
6319
6320 return newid;
6321 }
6322
6323 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6324 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6325 {
6326 struct necp_uuid_id_mapping *searchentry = NULL;
6327 struct necp_uuid_id_mapping *foundentry = NULL;
6328
6329 LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6330 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6331 foundentry = searchentry;
6332 break;
6333 }
6334 }
6335
6336 return foundentry;
6337 }
6338
6339 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6340 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6341 {
6342 struct necp_uuid_id_mapping *searchentry = NULL;
6343 struct necp_uuid_id_mapping *foundentry = NULL;
6344
6345 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6346 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--) {
6347 LIST_FOREACH(searchentry, uuid_list_head, chain) {
6348 if (searchentry->id == local_id) {
6349 foundentry = searchentry;
6350 break;
6351 }
6352 }
6353 }
6354
6355 return foundentry;
6356 }
6357
6358 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6359 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6360 {
6361 u_int32_t local_id = 0;
6362 struct necp_uuid_id_mapping *existing_mapping = NULL;
6363
6364 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6365
6366 if (allocated_mapping) {
6367 *allocated_mapping = FALSE;
6368 }
6369
6370 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6371 if (existing_mapping != NULL) {
6372 local_id = existing_mapping->id;
6373 os_ref_retain_locked(&existing_mapping->refcount);
6374 if (uuid_policy_table) {
6375 existing_mapping->table_usecount++;
6376 }
6377 } else {
6378 struct necp_uuid_id_mapping *new_mapping = NULL;
6379 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6380 Z_WAITOK | Z_NOFAIL);
6381 uuid_copy(new_mapping->uuid, uuid);
6382 new_mapping->id = necp_get_new_uuid_id(false);
6383 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6384 if (uuid_policy_table) {
6385 new_mapping->table_usecount = 1;
6386 } else {
6387 new_mapping->table_usecount = 0;
6388 }
6389
6390 LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6391
6392 if (allocated_mapping) {
6393 *allocated_mapping = TRUE;
6394 }
6395
6396 local_id = new_mapping->id;
6397 }
6398
6399 return local_id;
6400 }
6401
6402 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6403 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6404 {
6405 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6406
6407 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6408
6409 if (removed_mapping) {
6410 *removed_mapping = FALSE;
6411 }
6412
6413 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6414 if (existing_mapping != NULL) {
6415 if (uuid_policy_table) {
6416 existing_mapping->table_usecount--;
6417 }
6418 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6419 LIST_REMOVE(existing_mapping, chain);
6420 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6421 if (removed_mapping) {
6422 *removed_mapping = TRUE;
6423 }
6424 }
6425 return TRUE;
6426 }
6427
6428 return FALSE;
6429 }
6430
6431 static struct necp_uuid_id_mapping *
necp_uuid_get_null_service_id_mapping(void)6432 necp_uuid_get_null_service_id_mapping(void)
6433 {
6434 static struct necp_uuid_id_mapping null_mapping;
6435 uuid_clear(null_mapping.uuid);
6436 null_mapping.id = NECP_NULL_SERVICE_ID;
6437
6438 return &null_mapping;
6439 }
6440
6441 static struct necp_uuid_id_mapping *
necp_uuid_lookup_service_id_locked(uuid_t uuid)6442 necp_uuid_lookup_service_id_locked(uuid_t uuid)
6443 {
6444 struct necp_uuid_id_mapping *searchentry = NULL;
6445 struct necp_uuid_id_mapping *foundentry = NULL;
6446
6447 if (uuid_is_null(uuid)) {
6448 return necp_uuid_get_null_service_id_mapping();
6449 }
6450
6451 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6452 if (uuid_compare(searchentry->uuid, uuid) == 0) {
6453 foundentry = searchentry;
6454 break;
6455 }
6456 }
6457
6458 return foundentry;
6459 }
6460
6461 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)6462 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
6463 {
6464 struct necp_uuid_id_mapping *searchentry = NULL;
6465 struct necp_uuid_id_mapping *foundentry = NULL;
6466
6467 if (local_id == NECP_NULL_SERVICE_ID) {
6468 return necp_uuid_get_null_service_id_mapping();
6469 }
6470
6471 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6472 if (searchentry->id == local_id) {
6473 foundentry = searchentry;
6474 break;
6475 }
6476 }
6477
6478 return foundentry;
6479 }
6480
6481 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid)6482 necp_create_uuid_service_id_mapping(uuid_t uuid)
6483 {
6484 u_int32_t local_id = 0;
6485 struct necp_uuid_id_mapping *existing_mapping = NULL;
6486
6487 if (uuid_is_null(uuid)) {
6488 return NECP_NULL_SERVICE_ID;
6489 }
6490
6491 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6492
6493 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6494 if (existing_mapping != NULL) {
6495 local_id = existing_mapping->id;
6496 os_ref_retain_locked(&existing_mapping->refcount);
6497 } else {
6498 struct necp_uuid_id_mapping *new_mapping = NULL;
6499 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6500 Z_WAITOK | Z_NOFAIL);
6501 uuid_copy(new_mapping->uuid, uuid);
6502 new_mapping->id = necp_get_new_uuid_id(true);
6503 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6504
6505 LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
6506
6507 local_id = new_mapping->id;
6508 }
6509
6510 return local_id;
6511 }
6512
6513 static bool
necp_remove_uuid_service_id_mapping(uuid_t uuid)6514 necp_remove_uuid_service_id_mapping(uuid_t uuid)
6515 {
6516 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6517
6518 if (uuid_is_null(uuid)) {
6519 return TRUE;
6520 }
6521
6522 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6523
6524 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6525 if (existing_mapping != NULL) {
6526 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6527 LIST_REMOVE(existing_mapping, chain);
6528 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6529 }
6530 return TRUE;
6531 }
6532
6533 return FALSE;
6534 }
6535
6536 static bool
necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)6537 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
6538 {
6539 struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6540
6541 if (service_id == 0) {
6542 return TRUE;
6543 }
6544
6545 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6546
6547 existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
6548 if (existing_mapping != NULL) {
6549 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6550 LIST_REMOVE(existing_mapping, chain);
6551 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6552 }
6553 return TRUE;
6554 }
6555
6556 return FALSE;
6557 }
6558
6559 static bool
necp_kernel_socket_policies_update_uuid_table(void)6560 necp_kernel_socket_policies_update_uuid_table(void)
6561 {
6562 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6563
6564 if (necp_uuid_app_id_mappings_dirty) {
6565 uuid_t dummy_uuid = {};
6566 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6567 NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6568 return FALSE;
6569 }
6570
6571 if (necp_num_uuid_app_id_mappings > 0) {
6572 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6573 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--) {
6574 struct necp_uuid_id_mapping *mapping = NULL;
6575 LIST_FOREACH(mapping, uuid_list_head, chain) {
6576 if (mapping->table_usecount > 0 &&
6577 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6578 NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6579 }
6580 }
6581 }
6582 }
6583
6584 necp_uuid_app_id_mappings_dirty = FALSE;
6585 }
6586
6587 return TRUE;
6588 }
6589
6590 #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)
6591 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)6592 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)
6593 {
6594 struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6595 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6596
6597 new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6598 new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6599 new_kernel_policy->suborder = suborder;
6600 new_kernel_policy->order = order;
6601 new_kernel_policy->session_order = session_order;
6602 new_kernel_policy->session_pid = session_pid;
6603
6604 // Sanitize condition mask
6605 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6606 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6607 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6608 }
6609 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
6610 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
6611 }
6612 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6613 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6614 }
6615 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6616 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6617 }
6618 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6619
6620 // Set condition values
6621 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6622 new_kernel_policy->cond_policy_id = cond_policy_id;
6623 }
6624 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6625 if (cond_bound_interface) {
6626 ifnet_reference(cond_bound_interface);
6627 }
6628 new_kernel_policy->cond_bound_interface = cond_bound_interface;
6629 }
6630 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6631 new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6632 }
6633 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6634 new_kernel_policy->cond_protocol = cond_protocol;
6635 }
6636 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6637 SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
6638 }
6639 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6640 SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
6641 }
6642 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6643 new_kernel_policy->cond_local_prefix = cond_local_prefix;
6644 }
6645 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6646 SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
6647 }
6648 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6649 SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
6650 }
6651 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6652 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
6653 }
6654 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
6655 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
6656 }
6657 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
6658 new_kernel_policy->cond_scheme_port = cond_scheme_port;
6659 }
6660 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
6661 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
6662 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
6663 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
6664 }
6665 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
6666 new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
6667 }
6668
6669 new_kernel_policy->result = result;
6670 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
6671
6672 if (necp_debug) {
6673 NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
6674 }
6675 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
6676
6677 return new_kernel_policy ? new_kernel_policy->id : 0;
6678 }
6679
6680 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)6681 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
6682 {
6683 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6684 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6685
6686 if (policy_id == 0) {
6687 return NULL;
6688 }
6689
6690 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
6691 if (kernel_policy->id == policy_id) {
6692 return kernel_policy;
6693 }
6694 }
6695
6696 return NULL;
6697 }
6698
6699 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)6700 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
6701 {
6702 struct necp_kernel_ip_output_policy * __single policy = NULL;
6703
6704 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6705
6706 policy = necp_kernel_ip_output_policy_find(policy_id);
6707 if (policy) {
6708 LIST_REMOVE(policy, chain);
6709
6710 if (policy->cond_bound_interface) {
6711 ifnet_release(policy->cond_bound_interface);
6712 policy->cond_bound_interface = NULL;
6713 }
6714
6715 zfree(necp_ip_policy_zone, policy);
6716 return TRUE;
6717 }
6718
6719 return FALSE;
6720 }
6721
6722 static void
necp_kernel_ip_output_policies_dump_all(void)6723 necp_kernel_ip_output_policies_dump_all(void)
6724 {
6725 if (necp_debug) {
6726 struct necp_kernel_ip_output_policy *policy = NULL;
6727 int policy_i;
6728 int id_i;
6729 char result_string[MAX_RESULT_STRING_LEN];
6730 char proc_name_string[MAXCOMLEN + 1];
6731 memset(result_string, 0, MAX_RESULT_STRING_LEN);
6732 memset(proc_name_string, 0, MAXCOMLEN + 1);
6733
6734 NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
6735 NECPLOG0(LOG_DEBUG, "-----------\n");
6736 for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
6737 NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
6738 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++) {
6739 policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
6740 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
6741 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));
6742 }
6743 NECPLOG0(LOG_DEBUG, "-----------\n");
6744 }
6745 }
6746 }
6747
6748 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)6749 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
6750 {
6751 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6752 if (upper_policy->session_order != lower_policy->session_order) {
6753 // A skip cannot override a policy of a different session
6754 return FALSE;
6755 } else {
6756 if (upper_policy->result_parameter.skip_policy_order == 0 ||
6757 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
6758 // This policy is beyond the skip
6759 return FALSE;
6760 } else {
6761 // This policy is inside the skip
6762 return TRUE;
6763 }
6764 }
6765 }
6766
6767 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
6768 return TRUE;
6769 }
6770
6771 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)6772 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)
6773 {
6774 bool can_skip = FALSE;
6775 u_int32_t highest_skip_session_order = 0;
6776 u_int32_t highest_skip_order = 0;
6777 int i;
6778 for (i = 0; i < valid_indices; i++) {
6779 struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
6780
6781 // For policies in a skip window, we can't mark conflicting policies as unnecessary
6782 if (can_skip) {
6783 if (highest_skip_session_order != compared_policy->session_order ||
6784 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
6785 // If we've moved on to the next session, or passed the skip window
6786 highest_skip_session_order = 0;
6787 highest_skip_order = 0;
6788 can_skip = FALSE;
6789 } else {
6790 // If this policy is also a skip, in can increase the skip window
6791 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6792 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
6793 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6794 }
6795 }
6796 continue;
6797 }
6798 }
6799
6800 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6801 // This policy is a skip. Set the skip window accordingly
6802 can_skip = TRUE;
6803 highest_skip_session_order = compared_policy->session_order;
6804 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6805 }
6806
6807 // The result of the compared policy must be able to block out this policy result
6808 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
6809 continue;
6810 }
6811
6812 // If new policy matches All Interfaces, compared policy must also
6813 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
6814 continue;
6815 }
6816
6817 // If new policy matches Local Networks, compared policy must also
6818 if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
6819 continue;
6820 }
6821
6822 // Default makes lower policies unnecessary always
6823 if (compared_policy->condition_mask == 0) {
6824 return TRUE;
6825 }
6826
6827 // Compared must be more general than policy, and include only conditions within policy
6828 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
6829 continue;
6830 }
6831
6832 // Negative conditions must match for the overlapping conditions
6833 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
6834 continue;
6835 }
6836
6837 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
6838 compared_policy->cond_policy_id != policy->cond_policy_id) {
6839 continue;
6840 }
6841
6842 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
6843 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
6844 continue;
6845 }
6846
6847 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
6848 compared_policy->cond_protocol != policy->cond_protocol) {
6849 continue;
6850 }
6851
6852 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6853 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6854 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))) {
6855 continue;
6856 }
6857 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6858 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
6859 !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
6860 continue;
6861 }
6862 }
6863 }
6864
6865 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6866 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6867 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))) {
6868 continue;
6869 }
6870 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6871 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
6872 !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
6873 continue;
6874 }
6875 }
6876 }
6877
6878 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
6879 compared_policy->cond_scheme_port != policy->cond_scheme_port) {
6880 continue;
6881 }
6882
6883 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
6884 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
6885 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
6886 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
6887 continue;
6888 }
6889
6890 return TRUE;
6891 }
6892
6893 return FALSE;
6894 }
6895
6896 static bool
necp_kernel_ip_output_policies_reprocess(void)6897 necp_kernel_ip_output_policies_reprocess(void)
6898 {
6899 int i;
6900 int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
6901 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6902
6903 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6904
6905 // Reset mask to 0
6906 necp_kernel_ip_output_policies_condition_mask = 0;
6907 necp_kernel_ip_output_policies_count = 0;
6908 necp_kernel_ip_output_policies_non_id_count = 0;
6909
6910 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6911 if (necp_kernel_ip_output_policies_map[i] != NULL) {
6912 kfree_type(struct necp_kernel_ip_output_policy *,
6913 necp_kernel_ip_output_policies_map_counts[i] + 1,
6914 necp_kernel_ip_output_policies_map[i]);
6915 necp_kernel_ip_output_policies_map[i] = NULL;
6916 }
6917
6918 // Init counts
6919 necp_kernel_ip_output_policies_map_counts[i] = 0;
6920 }
6921
6922 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6923 // Update mask
6924 necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
6925 necp_kernel_ip_output_policies_count++;
6926
6927 /* Update bucket counts:
6928 * Non-id and SKIP policies will be added to all buckets
6929 * Add local networks policy to all buckets for incoming IP
6930 */
6931 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6932 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6933 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6934 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6935 necp_kernel_ip_output_policies_map_counts[i]++;
6936 }
6937 }
6938 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
6939 necp_kernel_ip_output_policies_non_id_count++;
6940 } else {
6941 necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
6942 }
6943 }
6944
6945 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6946 if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
6947 // Allocate a NULL-terminated array of policy pointers for each bucket
6948 necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
6949 necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
6950 if (necp_kernel_ip_output_policies_map[i] == NULL) {
6951 goto fail;
6952 }
6953 }
6954 bucket_current_free_index[i] = 0;
6955 }
6956
6957 u_int32_t current_session_order = 0;
6958 u_int32_t current_session_last_non_skip_policy = 0;
6959
6960 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6961 // For each new session, find the last non-skip policy. We can
6962 // avoid adding any skip policies that don't actually skip over
6963 // any non-skip policies.
6964 if (current_session_order != kernel_policy->session_order) {
6965 current_session_order = kernel_policy->session_order;
6966 current_session_last_non_skip_policy = 0;
6967
6968 struct necp_kernel_ip_output_policy *inner_policy = NULL;
6969 LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
6970 if (inner_policy->session_order < current_session_order) {
6971 continue;
6972 }
6973 if (inner_policy->session_order > current_session_order) {
6974 break;
6975 }
6976 if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6977 continue;
6978 }
6979
6980 current_session_last_non_skip_policy = inner_policy->order;
6981 }
6982 }
6983
6984 if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6985 if (current_session_last_non_skip_policy == 0) {
6986 // No useful policies to skip over, don't add
6987 continue;
6988 }
6989 if (kernel_policy->order >= current_session_last_non_skip_policy) {
6990 // Skip policy is after the last useful policy, don't add
6991 continue;
6992 }
6993 }
6994
6995 // Insert pointers into map
6996 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6997 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6998 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6999 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7000 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])) {
7001 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7002 bucket_current_free_index[i]++;
7003 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7004 }
7005 }
7006 } else {
7007 i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7008 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])) {
7009 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7010 bucket_current_free_index[i]++;
7011 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7012 }
7013 }
7014 }
7015
7016 if (bucket_current_free_index[0] == 0) {
7017 // No non-id policies were actually added
7018 necp_kernel_ip_output_policies_non_id_count = 0;
7019
7020 // Also check if no policies at all were added
7021 bool policies_added = FALSE;
7022 for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7023 if (bucket_current_free_index[i] != 0) {
7024 policies_added = TRUE;
7025 break;
7026 }
7027 }
7028 if (!policies_added) {
7029 necp_kernel_ip_output_policies_condition_mask = 0;
7030 necp_kernel_ip_output_policies_count = 0;
7031 }
7032 }
7033
7034 necp_kernel_ip_output_policies_dump_all();
7035 return TRUE;
7036
7037 fail:
7038 // Free memory, reset mask to 0
7039 necp_kernel_ip_output_policies_condition_mask = 0;
7040 necp_kernel_ip_output_policies_count = 0;
7041 necp_kernel_ip_output_policies_non_id_count = 0;
7042 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7043 if (necp_kernel_ip_output_policies_map[i] != NULL) {
7044 kfree_type(struct necp_kernel_ip_output_policy *,
7045 necp_kernel_ip_output_policies_map_counts[i] + 1,
7046 necp_kernel_ip_output_policies_map[i]);
7047 necp_kernel_ip_output_policies_map[i] = NULL;
7048 }
7049 }
7050 return FALSE;
7051 }
7052
7053 // Outbound Policy Matching
7054 // ---------------------
7055 struct substring {
7056 size_t length;
7057 char * __sized_by(length) string;
7058 };
7059
7060 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7061 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7062 {
7063 struct substring sub = {};
7064 char * __indexable ptr = string;
7065 size_t len = string ? length : 0;
7066
7067 while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7068 ptr++;
7069 len--;
7070 }
7071
7072 while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7073 len--;
7074 }
7075
7076 sub.string = ptr;
7077 sub.length = len;
7078 return sub;
7079 }
7080
7081 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7082 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7083 {
7084 size_t trimmed_domain_length = 0;
7085 char *trimmed_domain = NULL;
7086 struct substring sub = necp_trim_dots_and_stars(string, length);
7087
7088 trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7089 trimmed_domain_length = sub.length + 1;
7090 if (trimmed_domain == NULL) {
7091 return NULL;
7092 }
7093
7094 strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7095 trimmed_domain[sub.length] = 0;
7096
7097 return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7098 }
7099
7100 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7101 necp_count_dots(char * __sized_by(length)string, size_t length)
7102 {
7103 int dot_count = 0;
7104 size_t i = 0;
7105
7106 for (i = 0; i < length; i++) {
7107 if (string[i] == '.') {
7108 dot_count++;
7109 }
7110 }
7111
7112 return dot_count;
7113 }
7114
7115 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7116 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7117 {
7118 if (parent.length <= suffix.length) {
7119 return FALSE;
7120 }
7121
7122 size_t length_difference = (parent.length - suffix.length);
7123
7124 if (require_dot_before_suffix) {
7125 if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7126 return FALSE;
7127 }
7128 }
7129
7130 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7131 return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7132 }
7133
7134 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)7135 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7136 {
7137 if (hostname_substring.string == NULL || domain == NULL) {
7138 return hostname_substring.string == domain;
7139 }
7140
7141 struct substring domain_substring;
7142 domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7143 domain_substring.length = strlen(domain);
7144
7145 if (hostname_dot_count == domain_dot_count) {
7146 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7147 if (hostname_substring.length == domain_substring.length &&
7148 strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7149 return TRUE;
7150 }
7151 } else if (domain_dot_count < hostname_dot_count) {
7152 if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7153 return TRUE;
7154 }
7155 }
7156
7157 return FALSE;
7158 }
7159
7160 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7161 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7162 {
7163 if (hostname_string == NULL ||
7164 domain_string == NULL) {
7165 return false;
7166 }
7167
7168 struct substring hostname_substring;
7169 hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7170 hostname_substring.length = strlen(hostname_string);
7171
7172 return necp_hostname_matches_domain(hostname_substring,
7173 necp_count_dots(hostname_substring.string, hostname_substring.length),
7174 domain_string,
7175 necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7176 }
7177
7178 #define NECP_MAX_STRING_LEN 1024
7179
7180 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7181 necp_copy_string(char * __sized_by(length)string, size_t length)
7182 {
7183 size_t copied_string_length = 0;
7184 char * __sized_by(copied_string_length) copied_string = NULL;
7185
7186 if (length > NECP_MAX_STRING_LEN) {
7187 return NULL;
7188 }
7189
7190 copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7191 copied_string_length = length + 1;
7192 if (copied_string == NULL) {
7193 return NULL;
7194 }
7195
7196 memcpy(copied_string, string, length);
7197 copied_string[length] = 0;
7198
7199 return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7200 }
7201
7202 static u_int32_t
necp_get_primary_direct_interface_index(void)7203 necp_get_primary_direct_interface_index(void)
7204 {
7205 u_int32_t interface_index = IFSCOPE_NONE;
7206
7207 ifnet_head_lock_shared();
7208 struct ifnet *ordered_interface = NULL;
7209 TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7210 const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7211 if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7212 functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7213 // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7214 interface_index = ordered_interface->if_index;
7215 break;
7216 }
7217 }
7218 ifnet_head_done();
7219
7220 return interface_index;
7221 }
7222
7223 static inline bool
necp_task_has_match_entitlement(task_t task)7224 necp_task_has_match_entitlement(task_t task)
7225 {
7226 return task != NULL &&
7227 (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7228 IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7229 }
7230
7231 // Loopback traffic from certain entitled process will be dropped
7232 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7233 necp_task_has_loopback_drop_entitlement(task_t task)
7234 {
7235 bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7236 if (drop) {
7237 necp_drop_loopback_count++;
7238 }
7239 return drop;
7240 }
7241
7242 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7243 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7244 {
7245 coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7246
7247 if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7248 // No parent, nothing to do
7249 return;
7250 }
7251
7252 task_t __single lead_task = coalition_get_leader(coal);
7253 if (lead_task != NULL) {
7254 info->is_entitled = necp_task_has_match_entitlement(lead_task);
7255 task_deallocate(lead_task);
7256 }
7257 }
7258
7259 // Some processes, due to particular entitlements, require using an NECP client to
7260 // access networking. Returns true if the result should be a Drop.
7261 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7262 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7263 {
7264 if (necp_is_platform_binary(proc)) {
7265 // This check is currently for the "on-demand-install-capable"
7266 // entitlement, which by definition cannot be a built-in platform
7267 // binary.
7268 return false;
7269 }
7270
7271 task_t __single task = proc_task(proc ? proc : current_proc());
7272
7273 if (!info->has_client &&
7274 task != NULL &&
7275 IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7276 // Drop connections that don't use NECP clients and have the
7277 // com.apple.developer.on-demand-install-capable entitlement.
7278 // This effectively restricts those processes to only using
7279 // an NECP-aware path for networking.
7280 return true;
7281 } else {
7282 return false;
7283 }
7284 }
7285
7286 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7287 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7288 {
7289 if (!necp_restrict_multicast || proc == NULL) {
7290 return false;
7291 }
7292
7293 // Check for multicast/broadcast here
7294 if (info->remote_addr.sa.sa_family == AF_INET) {
7295 if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7296 info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7297 return false;
7298 }
7299 } else if (info->remote_addr.sa.sa_family == AF_INET6) {
7300 if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7301 return false;
7302 }
7303 } else {
7304 // Not IPv4/IPv6
7305 return false;
7306 }
7307
7308 if (necp_is_platform_binary(proc)) {
7309 return false;
7310 }
7311
7312 const uint32_t platform = proc_platform(proc);
7313 const uint32_t sdk = proc_sdk(proc);
7314
7315 // Enforce for iOS, linked on or after version 14
7316 // If the caller set `check_minor_version`, only enforce starting at 14.5
7317 if ((platform != PLATFORM_IOS ||
7318 sdk == 0 ||
7319 (sdk >> 16) < 14 ||
7320 (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7321 return false;
7322 }
7323
7324 // Allow entitled processes to use multicast
7325 task_t __single task = proc_task(proc);
7326 if (task != NULL &&
7327 IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7328 return false;
7329 }
7330
7331 const uint32_t min_sdk = proc_min_sdk(proc);
7332 NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7333
7334 return true;
7335 }
7336
7337 #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)
7338 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)7339 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)
7340 {
7341 memset(info, 0, sizeof(struct necp_socket_info));
7342
7343 info->pid = pid;
7344 info->pid_version = pid_version;
7345 info->uid = uid;
7346 info->real_uid = real_uid;
7347 info->protocol = protocol;
7348 info->bound_interface_index = bound_interface_index;
7349 info->traffic_class = traffic_class;
7350 info->has_client = has_client;
7351 info->has_system_signed_result = has_system_signed_result;
7352 info->drop_order = drop_order;
7353 info->client_flags = client_flags;
7354 info->is_loopback = is_loopback;
7355 info->is_delegated = is_delegated;
7356
7357 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7358 info->bound_interface_index != IFSCOPE_NONE) {
7359 ifnet_head_lock_shared();
7360 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7361 if (interface != NULL) {
7362 info->bound_interface_flags = interface->if_flags;
7363 info->bound_interface_eflags = interface->if_eflags;
7364 info->bound_interface_xflags = interface->if_xflags;
7365 }
7366 ifnet_head_done();
7367 }
7368
7369 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7370 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7371 if (existing_mapping) {
7372 info->application_id = existing_mapping->id;
7373 }
7374 }
7375
7376 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7377 if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7378 info->real_application_id = info->application_id;
7379 } else {
7380 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7381 if (existing_mapping) {
7382 info->real_application_id = existing_mapping->id;
7383 }
7384 }
7385 }
7386
7387 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7388 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7389 if (existing_mapping != NULL) {
7390 info->real_application_id = info->application_id;
7391 info->application_id = existing_mapping->id;
7392 info->used_responsible_pid = true;
7393 }
7394 }
7395
7396 if (info->used_responsible_pid) {
7397 proc = responsible_proc;
7398 }
7399
7400 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7401 info->is_entitled = necp_task_has_match_entitlement(task);
7402 if (!info->is_entitled) {
7403 // Task does not have entitlement, check the parent task
7404 necp_get_parent_is_entitled(task, info);
7405 }
7406 }
7407
7408 if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7409 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7410 if (necp_is_platform_binary(proc)) {
7411 info->is_platform_binary = true;
7412 } else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7413 info->is_platform_binary = true;
7414 info->used_responsible_pid = true;
7415 } else {
7416 info->is_platform_binary = false;
7417 }
7418 }
7419
7420 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7421 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7422 }
7423
7424 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7425 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7426 if (existing_mapping) {
7427 info->account_id = existing_mapping->id;
7428 }
7429 }
7430
7431 if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7432 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7433 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7434 info->domain = domain;
7435 }
7436
7437 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7438 info->url = url;
7439 }
7440
7441 if ((necp_data_tracing_level && necp_data_tracing_port) ||
7442 necp_restrict_multicast ||
7443 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7444 if (local_addr && local_addr->sa.sa_len > 0) {
7445 SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7446 if (local_port != 0) {
7447 info->local_addr.sin6.sin6_port = local_port;
7448 }
7449 } else {
7450 if (remote_addr && remote_addr->sa.sa_len > 0) {
7451 info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7452 info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7453 } else {
7454 info->local_addr.sin6.sin6_family = AF_INET6;
7455 info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7456 }
7457 if (local_port != 0) {
7458 info->local_addr.sin6.sin6_port = local_port;
7459 }
7460 }
7461 if (remote_addr && remote_addr->sa.sa_len > 0) {
7462 SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7463 if (remote_port != 0) {
7464 info->remote_addr.sin6.sin6_port = remote_port;
7465 }
7466 } else if (remote_port != 0) {
7467 info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7468 info->remote_addr.sin6.sin6_family = AF_INET6;
7469 info->remote_addr.sin6.sin6_port = remote_port;
7470 }
7471 }
7472
7473 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7474 info->scheme_port = scheme_port;
7475 }
7476 }
7477
7478 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7479 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7480 {
7481 struct kev_netpolicy_ifdenied ev_ifdenied;
7482
7483 bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7484
7485 ev_ifdenied.ev_data.epid = pid;
7486 uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7487 ev_ifdenied.ev_if_functional_type = if_functional_type;
7488
7489 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7490 }
7491
7492 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7493 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7494 {
7495 struct kev_netpolicy_netdenied ev_netdenied = {};
7496
7497 bzero(&ev_netdenied, sizeof(ev_netdenied));
7498
7499 ev_netdenied.ev_data.epid = pid;
7500 uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7501 ev_netdenied.ev_network_type = network_type;
7502
7503 netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7504 }
7505
7506 extern char *proc_name_address(void *p);
7507
7508 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7509 if (!has_checked_delegation_entitlement) { \
7510 has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7511 has_checked_delegation_entitlement = TRUE; \
7512 } \
7513 if (!has_delegation_entitlement) { \
7514 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7515 proc_name_address(_p), proc_pid(_p), _d); \
7516 break; \
7517 }
7518
7519 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)7520 necp_application_find_policy_match_internal(proc_t proc,
7521 u_int8_t * __sized_by(parameters_size)parameters,
7522 u_int32_t parameters_size,
7523 struct necp_aggregate_result *returned_result,
7524 u_int32_t *flags,
7525 u_int32_t *reason,
7526 u_int required_interface_index,
7527 const union necp_sockaddr_union *override_local_addr,
7528 const union necp_sockaddr_union *override_remote_addr,
7529 struct necp_client_endpoint *returned_v4_gateway,
7530 struct necp_client_endpoint *returned_v6_gateway,
7531 struct rtentry **returned_route, bool ignore_address,
7532 bool has_client,
7533 uuid_t *returned_override_euuid)
7534 {
7535 int error = 0;
7536 size_t offset = 0;
7537
7538 struct necp_kernel_socket_policy *matched_policy = NULL;
7539 struct necp_socket_info info = {};
7540 necp_kernel_policy_filter filter_control_unit = 0;
7541 necp_kernel_policy_result service_action = 0;
7542 necp_kernel_policy_service service = { 0, 0 };
7543
7544 u_int16_t protocol = 0;
7545 u_int32_t bound_interface_index = required_interface_index;
7546 u_int32_t traffic_class = 0;
7547 u_int32_t client_flags = 0;
7548 u_int16_t scheme_port = 0;
7549 union necp_sockaddr_union local_addr;
7550 union necp_sockaddr_union remote_addr;
7551 bool no_remote_addr = FALSE;
7552 u_int8_t remote_family = 0;
7553 bool no_local_addr = FALSE;
7554 u_int16_t local_port = 0;
7555 u_int16_t remote_port = 0;
7556 u_int32_t remote_endpoint_type = 0;
7557 bool remote_address_is_empty = false;
7558 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7559 bool is_delegated = false;
7560
7561 if (override_local_addr) {
7562 memcpy(&local_addr, override_local_addr, sizeof(local_addr));
7563 } else {
7564 memset(&local_addr, 0, sizeof(local_addr));
7565 }
7566 if (override_remote_addr) {
7567 memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
7568 } else {
7569 memset(&remote_addr, 0, sizeof(remote_addr));
7570 }
7571
7572 // Initialize UID, PID, and UUIDs to the current process
7573 uid_t uid = 0;
7574 uid_t real_uid = 0;
7575 kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
7576 if (cred != NULL) {
7577 uid = kauth_cred_getuid(cred);
7578 real_uid = uid;
7579 }
7580 task_t __single task = proc_task(proc);
7581 pid_t pid = proc_pid(proc);
7582 int32_t pid_version = proc_pidversion(proc);
7583 uuid_t application_uuid;
7584 uuid_clear(application_uuid);
7585 uuid_t real_application_uuid;
7586 uuid_clear(real_application_uuid);
7587 proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
7588 uuid_copy(application_uuid, real_application_uuid);
7589 uuid_t responsible_application_uuid;
7590 uuid_clear(responsible_application_uuid);
7591
7592 char *domain __null_terminated = NULL;
7593 char *url __null_terminated = NULL;
7594 char *account __null_terminated = NULL;
7595
7596 #define NECP_MAX_REQUIRED_AGENTS 16
7597 u_int32_t num_required_agent_types = 0;
7598 struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
7599 memset(&required_agent_types, 0, sizeof(required_agent_types));
7600
7601 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
7602 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
7603 memset(&netagent_ids, 0, sizeof(netagent_ids));
7604 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
7605 int netagent_cursor;
7606
7607 bool has_checked_delegation_entitlement = false;
7608 bool has_delegation_entitlement = false;
7609 bool has_system_signed_result = false;
7610
7611 proc_t responsible_proc = PROC_NULL;
7612 proc_t effective_proc = proc;
7613 bool release_eproc = false;
7614 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
7615
7616 u_int32_t flow_divert_aggregate_unit = 0;
7617
7618 if (returned_result == NULL) {
7619 if (cred != NULL) {
7620 kauth_cred_unref(&cred);
7621 }
7622 return EINVAL;
7623 }
7624
7625 if (returned_v4_gateway != NULL) {
7626 memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
7627 }
7628
7629 if (returned_v6_gateway != NULL) {
7630 memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
7631 }
7632
7633 if (returned_override_euuid != NULL) {
7634 uuid_clear(*returned_override_euuid);
7635 }
7636
7637 memset(returned_result, 0, sizeof(struct necp_aggregate_result));
7638
7639 u_int32_t drop_order = necp_process_drop_order(cred);
7640
7641 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
7642
7643 lck_rw_lock_shared(&necp_kernel_policy_lock);
7644 if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
7645 if (necp_drop_all_order > 0 || drop_order > 0) {
7646 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7647 lck_rw_done(&necp_kernel_policy_lock);
7648 if (cred != NULL) {
7649 kauth_cred_unref(&cred);
7650 }
7651 return 0;
7652 }
7653 }
7654 lck_rw_done(&necp_kernel_policy_lock);
7655
7656 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
7657 u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
7658 u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
7659
7660 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
7661 // If the length is larger than what can fit in the remaining parameters size, bail
7662 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
7663 break;
7664 }
7665
7666 if (length > 0) {
7667 u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
7668 if (value != NULL) {
7669 switch (type) {
7670 case NECP_CLIENT_PARAMETER_APPLICATION: {
7671 if (length >= sizeof(uuid_t)) {
7672 if (uuid_compare(application_uuid, value) == 0) {
7673 // No delegation
7674 break;
7675 }
7676
7677 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
7678
7679 is_delegated = true;
7680 uuid_copy(application_uuid, value);
7681 }
7682 break;
7683 }
7684 case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
7685 if (length >= sizeof(uuid_t)) {
7686 if (uuid_compare(real_application_uuid, value) == 0) {
7687 // No delegation
7688 break;
7689 }
7690
7691 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
7692
7693 is_delegated = true;
7694 uuid_copy(real_application_uuid, value);
7695 }
7696 break;
7697 }
7698 case NECP_CLIENT_PARAMETER_PID: {
7699 if (length >= sizeof(pid_t)) {
7700 if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
7701 // No delegation
7702 break;
7703 }
7704
7705 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
7706
7707 is_delegated = true;
7708 memcpy(&pid, value, sizeof(pid_t));
7709 }
7710 break;
7711 }
7712 case NECP_CLIENT_PARAMETER_UID: {
7713 if (length >= sizeof(uid_t)) {
7714 if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
7715 // No delegation
7716 break;
7717 }
7718
7719 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
7720
7721 is_delegated = true;
7722 memcpy(&uid, value, sizeof(uid_t));
7723 }
7724 break;
7725 }
7726 case NECP_CLIENT_PARAMETER_DOMAIN: {
7727 char *ptr = (char *)value;
7728 ptr[length - 1] = 0;
7729 domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
7730 break;
7731 }
7732 case NECP_CLIENT_PARAMETER_URL: {
7733 char *ptr = (char *)value;
7734 ptr[length - 1] = 0;
7735 url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
7736 break;
7737 }
7738 case NECP_CLIENT_PARAMETER_ACCOUNT: {
7739 char *ptr = (char *)value;
7740 ptr[length - 1] = 0;
7741 account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
7742 break;
7743 }
7744 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
7745 if (length >= sizeof(u_int32_t)) {
7746 memcpy(&traffic_class, value, sizeof(u_int32_t));
7747 }
7748 break;
7749 }
7750 case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
7751 if (length >= sizeof(u_int16_t)) {
7752 memcpy(&protocol, value, sizeof(u_int16_t));
7753 } else if (length >= sizeof(u_int8_t)) {
7754 memcpy(&protocol, value, sizeof(u_int8_t));
7755 }
7756 break;
7757 }
7758 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
7759 if (length <= IFXNAMSIZ && length > 0) {
7760 ifnet_t __single bound_interface = NULL;
7761 char interface_name[IFXNAMSIZ];
7762 memcpy(interface_name, value, length);
7763 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
7764 if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
7765 bound_interface_index = bound_interface->if_index;
7766 ifnet_release(bound_interface);
7767 }
7768 }
7769 break;
7770 }
7771 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
7772 if (ignore_address || override_local_addr) {
7773 break;
7774 }
7775
7776 if (length >= sizeof(struct necp_policy_condition_addr)) {
7777 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7778 if (necp_address_is_valid(&address_struct->address.sa)) {
7779 memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
7780 }
7781 }
7782 break;
7783 }
7784 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
7785 if (ignore_address || override_remote_addr) {
7786 break;
7787 }
7788
7789 if (length >= sizeof(struct necp_policy_condition_addr)) {
7790 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7791 if (necp_address_is_valid(&address_struct->address.sa)) {
7792 memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
7793 }
7794 }
7795 break;
7796 }
7797 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
7798 if (ignore_address || override_local_addr) {
7799 break;
7800 }
7801
7802 if (length >= sizeof(struct necp_client_endpoint)) {
7803 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7804 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
7805 endpoint->u.endpoint.endpoint_port != 0) {
7806 // Save port
7807 local_port = endpoint->u.endpoint.endpoint_port;
7808 }
7809 }
7810 break;
7811 }
7812 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
7813 if (ignore_address || override_remote_addr) {
7814 break;
7815 }
7816
7817 if (length >= sizeof(struct necp_client_endpoint)) {
7818 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7819 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
7820 remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
7821 if (endpoint->u.endpoint.endpoint_port != 0) {
7822 // Save port
7823 remote_port = endpoint->u.endpoint.endpoint_port;
7824 }
7825 } else if (necp_addr_is_empty(&endpoint->u.sa)) {
7826 remote_address_is_empty = true;
7827 }
7828 }
7829 break;
7830 }
7831 case NECP_CLIENT_PARAMETER_FLAGS: {
7832 if (length >= sizeof(client_flags)) {
7833 memcpy(&client_flags, value, sizeof(client_flags));
7834 }
7835 break;
7836 }
7837 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
7838 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
7839 if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
7840 break;
7841 }
7842 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
7843 memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
7844 num_required_agent_types++;
7845 }
7846 break;
7847 }
7848 case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
7849 if (length >= sizeof(scheme_port)) {
7850 memcpy(&scheme_port, value, sizeof(scheme_port));
7851 }
7852 break;
7853 }
7854 case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
7855 has_system_signed_result = true;
7856 struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
7857 if (length >= sizeof(struct necp_client_validatable)) {
7858 // Check for system-signed sign_type values
7859 if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
7860 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
7861 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
7862 has_system_signed_result = true;
7863 }
7864 }
7865 break;
7866 }
7867 default: {
7868 break;
7869 }
7870 }
7871 }
7872 }
7873
7874 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
7875 }
7876
7877 // Check for loopback exception
7878 if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
7879 if (necp_task_has_loopback_drop_entitlement(task)) {
7880 // Disallow certain entitled processes to send loopback traffic
7881 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7882 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7883 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7884 if (cred != NULL) {
7885 kauth_cred_unref(&cred);
7886 }
7887 return 0;
7888 }
7889 if (necp_pass_loopback > 0) {
7890 bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
7891 }
7892 } else if (bound_interface_index != IFSCOPE_NONE) {
7893 // Check for inter-process exception
7894 struct sockaddr *dst = SA(&remote_addr.sa);
7895 if (dst->sa_family == AF_INET6) {
7896 struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
7897 if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
7898 ifnet_head_lock_shared();
7899 ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
7900 if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
7901 bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
7902 }
7903 ifnet_head_done();
7904 }
7905 }
7906 }
7907
7908 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
7909 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7910 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7911 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
7912 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
7913 returned_result->routed_interface_index = lo_ifp->if_index;
7914 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7915 } else {
7916 returned_result->routed_interface_index = bound_interface_index;
7917 }
7918 if (cred != NULL) {
7919 kauth_cred_unref(&cred);
7920 }
7921 return 0;
7922 }
7923
7924 if (drop_order != 0) {
7925 if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
7926 client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
7927 ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
7928 // Allow listeners, inbound connections without remote addresses, and
7929 // application service connections to bypass the unentitled drop order,
7930 // to allow them to connect to application services (not directly over
7931 // physical networking interfaces)
7932 drop_order = 0;
7933 }
7934 }
7935
7936 if (proc_pid(effective_proc) != pid) {
7937 proc_t found_proc = proc_find(pid);
7938 if (found_proc != PROC_NULL) {
7939 effective_proc = found_proc;
7940 pid_version = proc_pidversion(effective_proc);
7941 release_eproc = true;
7942 }
7943 }
7944 #if defined(XNU_TARGET_OS_OSX)
7945 if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
7946 proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
7947 responsible_proc = proc_find(effective_proc->p_responsible_pid);
7948 }
7949 #endif /* defined(XNU_TARGET_OS_OSX) */
7950
7951 // Lock
7952 lck_rw_lock_shared(&necp_kernel_policy_lock);
7953
7954 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
7955 size_t route_rule_id_array_count = 0;
7956 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);
7957
7958 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
7959 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
7960
7961 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
7962 matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
7963 &info,
7964 &filter_control_unit,
7965 route_rule_id_array,
7966 &route_rule_id_array_count,
7967 MAX_AGGREGATE_ROUTE_RULES,
7968 &service_action,
7969 &service,
7970 netagent_ids,
7971 NECP_MAX_NETAGENTS,
7972 netagent_use_flags,
7973 NECP_MAX_NETAGENTS,
7974 required_agent_types,
7975 num_required_agent_types,
7976 info.used_responsible_pid ? responsible_proc : effective_proc,
7977 0,
7978 &skip_policy_id,
7979 NULL,
7980 &drop_dest_policy_result,
7981 &drop_all_bypass,
7982 &flow_divert_aggregate_unit,
7983 NULL,
7984 debug);
7985
7986 // Check for loopback exception again after the policy match
7987 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
7988 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
7989 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
7990 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
7991 returned_result->filter_control_unit = 0;
7992 } else {
7993 returned_result->filter_control_unit = filter_control_unit;
7994 }
7995
7996 if (flow_divert_aggregate_unit > 0) {
7997 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
7998 }
7999
8000 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8001 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8002 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8003 returned_result->routed_interface_index = lo_ifp->if_index;
8004 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8005 error = 0;
8006 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8007 goto done;
8008 }
8009
8010 if (matched_policy) {
8011 returned_result->policy_id = matched_policy->id;
8012 returned_result->skip_policy_id = skip_policy_id;
8013 returned_result->routing_result = matched_policy->result;
8014 memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8015 if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8016 uuid_copy(*returned_override_euuid, responsible_application_uuid);
8017 }
8018 } else {
8019 bool drop_all = false;
8020 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8021 // Mark socket as a drop if drop_all is set
8022 drop_all = true;
8023 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8024 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8025 }
8026 }
8027 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8028 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8029 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8030 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8031 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8032 } else {
8033 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8034 returned_result->skip_policy_id = skip_policy_id;
8035 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8036 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8037 }
8038 }
8039 if (necp_check_missing_client_drop(proc, &info) ||
8040 necp_check_restricted_multicast_drop(proc, &info, false)) {
8041 // Mark as drop
8042 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8043 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8044 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8045 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8046 }
8047 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8048 returned_result->filter_control_unit = 0;
8049 } else {
8050 returned_result->filter_control_unit = filter_control_unit;
8051 }
8052
8053 if (flow_divert_aggregate_unit > 0) {
8054 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8055 }
8056
8057 returned_result->service_action = service_action;
8058
8059 // Fetch service registration
8060 if (service.identifier != 0) {
8061 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
8062 if (mapping != NULL) {
8063 struct necp_service_registration *service_registration = NULL;
8064 uuid_copy(returned_result->service_uuid, mapping->uuid);
8065 returned_result->service_data = service.data;
8066 if (service.identifier == NECP_NULL_SERVICE_ID) {
8067 // NULL service is always 'registered'
8068 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8069 } else {
8070 LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
8071 if (service.identifier == service_registration->service_id) {
8072 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8073 break;
8074 }
8075 }
8076 }
8077 }
8078 }
8079
8080 // Handle netagents
8081 size_t netagent_i = 0;
8082 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8083 struct necp_uuid_id_mapping *mapping = NULL;
8084 u_int32_t netagent_id = netagent_ids[netagent_cursor];
8085 if (netagent_id == 0) {
8086 continue;
8087 }
8088 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8089 if (mapping != NULL) {
8090 uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8091 returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8092 netagent_i++;
8093 }
8094
8095 // If the flags say to remove, clear the local copy
8096 if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8097 netagent_ids[netagent_cursor] = 0;
8098 }
8099 }
8100
8101 // Do routing evaluation
8102 u_int output_bound_interface = bound_interface_index;
8103 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8104 output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8105 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8106 output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8107 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8108 output_bound_interface = necp_get_primary_direct_interface_index();
8109 if (output_bound_interface == IFSCOPE_NONE) {
8110 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8111 } else {
8112 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8113 returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8114 }
8115 }
8116
8117 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8118 returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8119 if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8120 // Trigger the event that we dropped due to a local network policy
8121 #if defined(XNU_TARGET_OS_OSX)
8122 bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8123 necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8124 should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8125 NETPOLICY_NETWORKTYPE_LOCAL);
8126 #else
8127 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8128 #endif
8129 }
8130 if (reason != NULL) {
8131 *reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8132 }
8133 }
8134
8135 if (local_addr.sa.sa_len == 0 ||
8136 (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8137 (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8138 no_local_addr = TRUE;
8139 }
8140
8141 if (remote_addr.sa.sa_len == 0 ||
8142 (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8143 (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8144 no_remote_addr = TRUE;
8145 remote_family = remote_addr.sa.sa_family;
8146 }
8147
8148 returned_result->routed_interface_index = 0;
8149 struct rtentry *rt = NULL;
8150 if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8151 // Treat the output bound interface as the routed interface for local address
8152 // validation later.
8153 returned_result->routed_interface_index = output_bound_interface;
8154 } else {
8155 if (no_remote_addr) {
8156 memset(&remote_addr, 0, sizeof(remote_addr));
8157 if (remote_family == AF_INET6) {
8158 // Reset address to ::
8159 remote_addr.sa.sa_family = AF_INET6;
8160 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8161 } else {
8162 // Reset address to 0.0.0.0
8163 remote_addr.sa.sa_family = AF_INET;
8164 remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8165 }
8166 }
8167
8168 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8169 output_bound_interface);
8170
8171 if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8172 IS_INTF_CLAT46(rt->rt_ifp)) {
8173 rtfree(rt);
8174 rt = NULL;
8175 returned_result->routed_interface_index = 0;
8176 }
8177
8178 if (no_remote_addr && remote_family == AF_UNSPEC &&
8179 (rt == NULL || rt->rt_ifp == NULL)) {
8180 // Route lookup for default IPv4 failed, try IPv6
8181
8182 // Cleanup old route if necessary
8183 if (rt != NULL) {
8184 rtfree(rt);
8185 rt = NULL;
8186 }
8187
8188 // Reset address to ::
8189 memset(&remote_addr, 0, sizeof(remote_addr));
8190 remote_addr.sa.sa_family = AF_INET6;
8191 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8192
8193 // Get route
8194 rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8195 output_bound_interface);
8196 }
8197
8198 if (rt != NULL &&
8199 rt->rt_ifp != NULL) {
8200 returned_result->routed_interface_index = rt->rt_ifp->if_index;
8201 /*
8202 * For local addresses, we allow the interface scope to be
8203 * either the loopback interface or the interface hosting the
8204 * local address.
8205 */
8206 if (bound_interface_index != IFSCOPE_NONE &&
8207 rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8208 (output_bound_interface == lo_ifp->if_index ||
8209 rt->rt_ifp->if_index == lo_ifp->if_index ||
8210 rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8211 struct sockaddr_storage dst;
8212 unsigned int ifscope = bound_interface_index;
8213
8214 /*
8215 * Transform dst into the internal routing table form
8216 */
8217 (void) sa_copy(SA(&remote_addr),
8218 &dst, &ifscope);
8219
8220 if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8221 rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8222 returned_result->routed_interface_index =
8223 bound_interface_index;
8224 }
8225 }
8226 }
8227 }
8228
8229 if (returned_result->routed_interface_index != 0 &&
8230 returned_result->routed_interface_index != lo_ifp->if_index && // Loopback can accept any local address
8231 !no_local_addr) {
8232 // Transform local_addr into the ifaddr form
8233 // IPv6 Scope IDs are always embedded in the ifaddr list
8234 struct sockaddr_storage local_address_sanitized;
8235 u_int ifscope = IFSCOPE_NONE;
8236 (void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8237 SIN(&local_address_sanitized)->sin_port = 0;
8238 if (local_address_sanitized.ss_family == AF_INET6) {
8239 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8240 SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8241 }
8242 }
8243
8244 // Validate local address on routed interface
8245 struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8246 if (ifa == NULL) {
8247 // Interface address not found, reject route
8248 returned_result->routed_interface_index = 0;
8249 if (rt != NULL) {
8250 rtfree(rt);
8251 rt = NULL;
8252 }
8253 } else {
8254 ifaddr_release(ifa);
8255 ifa = NULL;
8256 }
8257 }
8258
8259 if (flags != NULL) {
8260 #if SKYWALK
8261 if (kernel_is_macos_or_server()) {
8262 enum net_filter_event_subsystems filters = net_filter_event_get_state();
8263
8264 if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8265 *flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8266 }
8267 if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8268 *flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8269 }
8270 if (filters & NET_FILTER_EVENT_ALF) {
8271 *flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8272 }
8273 if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8274 *flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8275 }
8276 }
8277 #endif /* SKYWALK */
8278 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8279 // Check for local/direct
8280 bool is_local = FALSE;
8281 if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8282 is_local = TRUE;
8283 } else if (returned_result->routed_interface_index != 0 &&
8284 !no_remote_addr) {
8285 // Clean up the address before comparison with interface addresses
8286
8287 // Transform remote_addr into the ifaddr form
8288 // IPv6 Scope IDs are always embedded in the ifaddr list
8289 struct sockaddr_storage remote_address_sanitized;
8290 u_int ifscope = IFSCOPE_NONE;
8291 (void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8292 SIN(&remote_address_sanitized)->sin_port = 0;
8293 if (remote_address_sanitized.ss_family == AF_INET6) {
8294 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8295 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8296 }
8297 }
8298
8299 // Check if remote address is an interface address
8300 struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8301 if (ifa != NULL && ifa->ifa_ifp != NULL) {
8302 u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8303 if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8304 if_index_for_remote_addr == lo_ifp->if_index) {
8305 is_local = TRUE;
8306 }
8307 }
8308 if (ifa != NULL) {
8309 ifaddr_release(ifa);
8310 ifa = NULL;
8311 }
8312 }
8313
8314 if (is_local) {
8315 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8316 } else if (rt != NULL) {
8317 if (rt->rt_flags & RTF_GLOBAL) {
8318 *flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8319 } else if (!(rt->rt_flags & RTF_GATEWAY) &&
8320 (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8321 // Route is directly accessible
8322 *flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8323 }
8324 }
8325
8326 if (rt != NULL &&
8327 rt->rt_ifp != NULL) {
8328 // Check probe status
8329 if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8330 *flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8331 }
8332
8333 if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8334 struct if_cellular_status_v1 *ifsr;
8335
8336 ifnet_lock_shared(rt->rt_ifp);
8337 lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8338
8339 if (rt->rt_ifp->if_link_status != NULL) {
8340 ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8341
8342 if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8343 if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8344 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8345 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8346 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8347 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8348 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8349 }
8350 }
8351 }
8352 lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8353 ifnet_lock_done(rt->rt_ifp);
8354 }
8355
8356 // Check link quality
8357 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8358 (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8359 rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8360 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8361 }
8362
8363 // Check QoS marking (fastlane)
8364 for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8365 if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8366 *flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8367 // If the route can use QoS markings, stop iterating route rules
8368 break;
8369 }
8370 }
8371
8372 if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8373 *flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8374 }
8375
8376 if (traffic_class == SO_TC_BK_SYS) {
8377 // Block BK_SYS traffic if interface is throttled
8378 u_int32_t throttle_level = 0;
8379 if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8380 if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8381 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8382 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8383 }
8384 }
8385 }
8386 }
8387 }
8388
8389 u_int interface_to_check = returned_result->routed_interface_index;
8390 if (interface_to_check == 0) {
8391 interface_to_check = output_bound_interface;
8392 }
8393 union necp_sockaddr_union default_address;
8394 struct rtentry *v4Route = NULL;
8395 struct rtentry *v6Route = NULL;
8396
8397 memset(&default_address, 0, sizeof(default_address));
8398
8399 // Reset address to 0.0.0.0
8400 default_address.sa.sa_family = AF_INET;
8401 default_address.sa.sa_len = sizeof(struct sockaddr_in);
8402 v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8403 returned_result->routed_interface_index);
8404
8405 // Reset address to ::
8406 default_address.sa.sa_family = AF_INET6;
8407 default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8408 v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8409 returned_result->routed_interface_index);
8410
8411 if (v4Route != NULL) {
8412 if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8413 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8414 }
8415 if (returned_v4_gateway != NULL &&
8416 v4Route->rt_gateway != NULL &&
8417 v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8418 memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8419 memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8420 }
8421 rtfree(v4Route);
8422 v4Route = NULL;
8423 }
8424
8425 if (v6Route != NULL) {
8426 if (v6Route->rt_ifp != NULL) {
8427 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8428
8429 if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8430 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8431 }
8432 }
8433 if (returned_v6_gateway != NULL &&
8434 v6Route->rt_gateway != NULL &&
8435 v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8436 SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8437 }
8438 rtfree(v6Route);
8439 v6Route = NULL;
8440 }
8441 }
8442
8443 // Take two passes through the rule list: first for rules that don't match based on agents,
8444 // second for rules that match based on agents. Since rules can modify the agent list itself,
8445 // this makes the logic more deterministic. This allows a non-agent matching rule to remove
8446 // an agent before it is used for matching later.
8447 size_t route_rule_index = 0;
8448 bool second_pass = false;
8449 while (route_rule_index < route_rule_id_array_count) {
8450 bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8451 if (rule_matches_agents != second_pass) {
8452 // Process rules that match based on agents only in the second pass
8453 route_rule_index++;
8454 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8455 route_rule_index = 0;
8456 second_pass = true;
8457 }
8458 continue;
8459 }
8460
8461 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8462 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);
8463 if (!route_is_allowed) {
8464 // If the route is blocked, treat the lookup as a drop
8465 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8466 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8467
8468 if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8469 if (reason != NULL) {
8470 if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8471 *reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8472 } else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8473 *reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8474 }
8475 }
8476 necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8477 }
8478 // If the route gets denied, stop matching rules
8479 break;
8480 }
8481
8482 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8483 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8484 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8485 route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8486 if (flow_divert_control_unit != 0) {
8487 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8488 returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8489 }
8490 if (flow_divert_aggregate_unit != 0) {
8491 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8492 }
8493 }
8494
8495 // Check if there is a route rule that adds or removes an agent
8496 bool remove = false;
8497 u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8498 if (netagent_id != 0) {
8499 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8500 if (mapping != NULL) {
8501 bool agent_already_present = false;
8502 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8503 if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8504 // Found the agent already present
8505 agent_already_present = true;
8506 if (remove) {
8507 // Mark as remove if necessary
8508 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8509 }
8510 } else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8511 // Found open slot
8512 if (!agent_already_present) {
8513 uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8514 if (remove) {
8515 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8516 } else {
8517 returned_result->netagent_use_flags[netagent_cursor] = 0;
8518 }
8519 }
8520 break;
8521 }
8522 }
8523 }
8524
8525 // Update the local netagent_ids array for future evaluations
8526 if (remove) {
8527 // Check if the agent ID is in the array, and remove it
8528 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8529 if (netagent_id == netagent_ids[netagent_cursor]) {
8530 netagent_ids[netagent_cursor] = 0;
8531 }
8532 }
8533 } else {
8534 // Check if the agent ID is not yet in the array, and add it
8535 bool found = false;
8536 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8537 if (netagent_id == netagent_ids[netagent_cursor]) {
8538 found = true;
8539 break;
8540 }
8541 }
8542 if (!found) {
8543 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8544 if (netagent_ids[netagent_cursor] == 0) {
8545 // Empty slot, add the agent
8546 netagent_ids[netagent_cursor] = netagent_id;
8547 break;
8548 }
8549 }
8550 }
8551 }
8552 }
8553
8554 route_rule_index++;
8555 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8556 route_rule_index = 0;
8557 second_pass = true;
8558 }
8559 }
8560
8561 if (rt != NULL && rt->rt_ifp != NULL) {
8562 const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8563 const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8564 const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8565 IFNET_IS_EXPENSIVE(rt->rt_ifp));
8566 const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8567 IFNET_IS_CONSTRAINED(rt->rt_ifp));
8568 const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
8569 IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
8570 !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT)));
8571
8572 const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
8573 if (!is_listener && !is_browser) {
8574 if (reason != NULL) {
8575 if (expensive_prohibited) {
8576 *reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8577 } else if (constrained_prohibited) {
8578 *reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8579 } else if (ultra_constrained_not_allowed) {
8580 *reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8581 }
8582 }
8583 if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
8584 // If a property of the interface was not allowed, treat it as a drop
8585 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8586 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8587 }
8588 }
8589 }
8590
8591 if (rt != NULL) {
8592 if (returned_route != NULL) {
8593 *returned_route = rt;
8594 } else {
8595 rtfree(rt);
8596 }
8597 rt = NULL;
8598 }
8599
8600 done:
8601 // Unlock
8602 lck_rw_done(&necp_kernel_policy_lock);
8603
8604 if (release_eproc && effective_proc != PROC_NULL) {
8605 proc_rele(effective_proc);
8606 }
8607 #if defined(XNU_TARGET_OS_OSX)
8608 if (responsible_proc != PROC_NULL) {
8609 proc_rele(responsible_proc);
8610 }
8611 #endif
8612
8613 if (cred != NULL) {
8614 kauth_cred_unref(&cred);
8615 }
8616
8617 return error;
8618 }
8619
8620 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)8621 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
8622 {
8623 struct rtentry *rt = NULL;
8624 bool is_local = FALSE;
8625
8626 if (remote_addr == NULL) {
8627 return NULL;
8628 }
8629
8630 if (remote_addr->sa.sa_len == 0 ||
8631 (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8632 (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8633 return FALSE;
8634 }
8635
8636 // Lookup route regardless of the scoped interface to check if
8637 // remote address is in a local network.
8638 rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
8639
8640 if (rt == NULL) {
8641 goto done;
8642 }
8643 if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
8644 goto free_rt;
8645 }
8646 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
8647
8648 free_rt:
8649 rtfree(rt);
8650
8651 done:
8652 return is_local;
8653 }
8654
8655 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)8656 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
8657 necp_app_id app_id,
8658 necp_app_id real_app_id,
8659 uint8_t is_entitled,
8660 u_int32_t account_id,
8661 struct substring domain,
8662 u_int8_t domain_dot_count,
8663 const char *url __null_terminated,
8664 pid_t pid,
8665 int32_t pid_version,
8666 uid_t uid,
8667 uid_t real_uid,
8668 u_int32_t bound_interface_index,
8669 u_int32_t traffic_class,
8670 u_int16_t protocol,
8671 union necp_sockaddr_union *local,
8672 union necp_sockaddr_union *remote,
8673 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
8674 u_int32_t num_required_agent_types,
8675 bool has_client,
8676 uint32_t client_flags,
8677 int is_platform_binary,
8678 bool has_signed_result,
8679 proc_t proc,
8680 u_int16_t pf_tag,
8681 u_int16_t scheme_port,
8682 struct rtentry *rt,
8683 bool is_loopback,
8684 int debug,
8685 bool real_is_platform_binary,
8686 u_int32_t bound_interface_flags,
8687 u_int32_t bound_interface_eflags,
8688 u_int32_t bound_interface_xflags,
8689 struct necp_socket_info *info,
8690 bool is_delegated,
8691 struct socket *socket)
8692 {
8693 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
8694 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
8695 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
8696 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
8697 "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
8698 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
8699 if (bound_interface_index == cond_bound_interface_index) {
8700 // No match, matches forbidden interface
8701 return FALSE;
8702 }
8703 } else {
8704 if (bound_interface_index != cond_bound_interface_index) {
8705 // No match, does not match required interface
8706 return FALSE;
8707 }
8708 }
8709 }
8710 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
8711 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8712 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
8713 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8714 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
8715 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8716 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
8717 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
8718 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
8719 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
8720 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
8721 // No match, matches some forbidden interface flags
8722 return FALSE;
8723 }
8724 } else {
8725 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
8726 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
8727 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
8728 // No match, does not match some required interface xflags
8729 return FALSE;
8730 }
8731 }
8732 }
8733 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
8734 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
8735 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
8736 if (bound_interface_index != 0) {
8737 // No match, requires a non-bound packet
8738 return FALSE;
8739 }
8740 }
8741 }
8742
8743 if (kernel_policy->condition_mask == 0) {
8744 return TRUE;
8745 }
8746
8747 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
8748 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
8749 "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
8750 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
8751 if (app_id == kernel_policy->cond_app_id) {
8752 // No match, matches forbidden application
8753 return FALSE;
8754 }
8755 } else {
8756 if (app_id != kernel_policy->cond_app_id) {
8757 // No match, does not match required application
8758 return FALSE;
8759 }
8760 }
8761
8762 // Check signing identifier only after APP ID matched
8763 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
8764 kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
8765 u_int8_t matched = necp_boolean_state_false;
8766 const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
8767 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
8768 "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
8769 kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
8770 signing_id ? signing_id : "<n/a>");
8771 if (signing_id != NULL) {
8772 if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
8773 matched = necp_boolean_state_true;
8774 }
8775 }
8776
8777 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
8778 if (matched == necp_boolean_state_true) {
8779 return FALSE;
8780 }
8781 } else {
8782 if (matched != necp_boolean_state_true) {
8783 return FALSE;
8784 }
8785 }
8786 }
8787 }
8788
8789 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
8790 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
8791 "NECP_KERNEL_CONDITION_REAL_APP_ID",
8792 kernel_policy->cond_real_app_id, real_app_id);
8793 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
8794 if (real_app_id == kernel_policy->cond_real_app_id) {
8795 // No match, matches forbidden application
8796 return FALSE;
8797 }
8798 } else {
8799 if (real_app_id != kernel_policy->cond_real_app_id) {
8800 // No match, does not match required application
8801 return FALSE;
8802 }
8803 }
8804 }
8805
8806 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
8807 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
8808 if (!has_client) {
8809 return FALSE;
8810 }
8811 }
8812
8813 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
8814 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
8815 if (!is_entitled) {
8816 // Process is missing entitlement
8817 return FALSE;
8818 }
8819 }
8820
8821 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
8822 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);
8823 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
8824 if (is_platform_binary) {
8825 // Process is platform binary
8826 return FALSE;
8827 }
8828 } else {
8829 if (!is_platform_binary) {
8830 // Process is not platform binary
8831 return FALSE;
8832 }
8833 }
8834 }
8835
8836 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
8837 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
8838 if (has_signed_result == 0) {
8839 // Client did not have a system-signed result
8840 return FALSE;
8841 }
8842 }
8843
8844 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
8845 if (proc != NULL) {
8846 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
8847 kernel_policy->cond_sdk_version.platform,
8848 kernel_policy->cond_sdk_version.min_version,
8849 kernel_policy->cond_sdk_version.version,
8850 proc_platform(proc),
8851 proc_min_sdk(proc),
8852 proc_sdk(proc));
8853 if (kernel_policy->cond_sdk_version.platform != 0) {
8854 if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
8855 // Process does not match platform
8856 return FALSE;
8857 }
8858 }
8859
8860 if (kernel_policy->cond_sdk_version.min_version != 0) {
8861 if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
8862 // Process min version is older than required min version
8863 return FALSE;
8864 }
8865 }
8866
8867 if (kernel_policy->cond_sdk_version.version != 0) {
8868 if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
8869 // Process SDK version is older than required version
8870 return FALSE;
8871 }
8872 }
8873 }
8874 }
8875
8876 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
8877 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
8878 if (kernel_policy->cond_custom_entitlement != NULL) {
8879 if (proc == NULL) {
8880 // No process found, cannot check entitlement
8881 return FALSE;
8882 }
8883 task_t __single task = proc_task(proc);
8884 if (task == NULL ||
8885 !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
8886 // Process is missing custom entitlement
8887 return FALSE;
8888 }
8889 }
8890 }
8891
8892 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8893 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
8894 "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
8895 // Exact match requires the number of dots to match (no suffix matching allowed)
8896 bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
8897 necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
8898 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8899 if (domain_matches) {
8900 // No match, matches forbidden domain
8901 return FALSE;
8902 }
8903 } else {
8904 if (!domain_matches) {
8905 // No match, does not match required domain
8906 return FALSE;
8907 }
8908 }
8909 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8910 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
8911 "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
8912 bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
8913 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8914 if (domain_matches) {
8915 // No match, matches forbidden domain
8916 return FALSE;
8917 }
8918 } else {
8919 if (!domain_matches) {
8920 // No match, does not match required domain
8921 return FALSE;
8922 }
8923 }
8924 }
8925
8926 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8927 struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
8928 if (filter != NULL && filter->filter != NULL) {
8929 bool domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
8930 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8931 if (domain_matches) {
8932 // No match, matches forbidden domain
8933 return FALSE;
8934 }
8935 } else {
8936 if (!domain_matches) {
8937 // No match, does not match required domain
8938 return FALSE;
8939 }
8940 }
8941 }
8942 }
8943
8944 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
8945 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
8946 "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
8947 bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
8948 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
8949 if (url_matches) {
8950 // No match, matches forbidden url
8951 return FALSE;
8952 }
8953 } else {
8954 if (!url_matches) {
8955 // No match, does not match required url
8956 return FALSE;
8957 }
8958 }
8959 }
8960
8961 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8962 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
8963 "NECP_KERNEL_CONDITION_ACCOUNT_ID",
8964 kernel_policy->cond_account_id, account_id);
8965 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8966 if (account_id == kernel_policy->cond_account_id) {
8967 // No match, matches forbidden account
8968 return FALSE;
8969 }
8970 } else {
8971 if (account_id != kernel_policy->cond_account_id) {
8972 // No match, does not match required account
8973 return FALSE;
8974 }
8975 }
8976 }
8977
8978 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
8979 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
8980 "NECP_KERNEL_CONDITION_PID",
8981 kernel_policy->cond_pid, pid);
8982 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
8983 if (pid == kernel_policy->cond_pid) {
8984 // No match, matches forbidden pid
8985 return FALSE;
8986 }
8987 if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
8988 return FALSE;
8989 }
8990 } else {
8991 if (pid != kernel_policy->cond_pid) {
8992 // No match, does not match required pid
8993 return FALSE;
8994 }
8995 if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
8996 return FALSE;
8997 }
8998 }
8999 }
9000
9001 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9002 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9003 "NECP_KERNEL_CONDITION_UID",
9004 kernel_policy->cond_uid, uid);
9005 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9006 if (uid == kernel_policy->cond_uid) {
9007 // No match, matches forbidden uid
9008 return FALSE;
9009 }
9010 } else {
9011 if (uid != kernel_policy->cond_uid) {
9012 // No match, does not match required uid
9013 return FALSE;
9014 }
9015 }
9016 }
9017
9018 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9019 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9020 "NECP_KERNEL_CONDITION_REAL_UID",
9021 kernel_policy->cond_real_uid, real_uid);
9022 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9023 if (real_uid == kernel_policy->cond_real_uid) {
9024 // No match, matches forbidden uid
9025 return FALSE;
9026 }
9027 } else {
9028 if (real_uid != kernel_policy->cond_real_uid) {
9029 // No match, does not match required uid
9030 return FALSE;
9031 }
9032 }
9033 }
9034
9035 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9036 NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9037 kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9038 traffic_class, 0, 0);
9039 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9040 if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9041 traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9042 // No match, matches forbidden traffic class
9043 return FALSE;
9044 }
9045 } else {
9046 if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9047 traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9048 // No match, does not match required traffic class
9049 return FALSE;
9050 }
9051 }
9052 }
9053
9054 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9055 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9056 "NECP_KERNEL_CONDITION_PROTOCOL",
9057 kernel_policy->cond_protocol, protocol);
9058 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9059 if (protocol == kernel_policy->cond_protocol) {
9060 // No match, matches forbidden protocol
9061 return FALSE;
9062 }
9063 } else {
9064 if (protocol != kernel_policy->cond_protocol) {
9065 // No match, does not match required protocol
9066 return FALSE;
9067 }
9068 }
9069 }
9070
9071 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9072 NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9073 kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9074 "n/a", "n/a", "n/a");
9075 bool matches_agent_type = FALSE;
9076 for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9077 struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9078 if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9079 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) &&
9080 (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9081 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)) {
9082 // Found a required agent that matches
9083 matches_agent_type = TRUE;
9084 break;
9085 }
9086 }
9087 if (!matches_agent_type) {
9088 return FALSE;
9089 }
9090 }
9091
9092 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9093 bool is_local = FALSE;
9094 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9095
9096 if (rt != NULL) {
9097 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9098 } else {
9099 is_local = necp_is_route_local(remote, include_local_addresses);
9100 }
9101 if (info != NULL) {
9102 info->is_local = is_local;
9103 }
9104
9105 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);
9106 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9107 if (is_local) {
9108 // Match local-networks, fail
9109 return FALSE;
9110 }
9111 } else {
9112 if (!is_local) {
9113 // Either no route to validate or no match for local networks
9114 return FALSE;
9115 }
9116 }
9117 }
9118
9119 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9120 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9121 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9122 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9123 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9124 if (inRange) {
9125 return FALSE;
9126 }
9127 } else {
9128 if (!inRange) {
9129 return FALSE;
9130 }
9131 }
9132 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9133 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9134 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);
9135 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9136 if (inSubnet) {
9137 return FALSE;
9138 }
9139 } else {
9140 if (!inSubnet) {
9141 return FALSE;
9142 }
9143 }
9144 }
9145 }
9146
9147 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9148 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9149 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9150 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9151 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9152 if (inRange) {
9153 return FALSE;
9154 }
9155 } else {
9156 if (!inRange) {
9157 return FALSE;
9158 }
9159 }
9160 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9161 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9162 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);
9163 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9164 if (inSubnet) {
9165 return FALSE;
9166 }
9167 } else {
9168 if (!inSubnet) {
9169 return FALSE;
9170 }
9171 }
9172 }
9173 }
9174
9175 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9176 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9177 "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9178 kernel_policy->cond_client_flags, client_flags);
9179 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9180 if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9181 // Flags do match, and condition is negative, fail.
9182 return FALSE;
9183 }
9184 } else {
9185 if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9186 // Flags do not match, fail.
9187 return FALSE;
9188 }
9189 }
9190 }
9191
9192 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9193 bool isEmpty = necp_addr_is_empty(SA(local));
9194 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9195 "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9196 0, isEmpty);
9197 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9198 if (isEmpty) {
9199 return FALSE;
9200 }
9201 } else {
9202 if (!isEmpty) {
9203 return FALSE;
9204 }
9205 }
9206 }
9207
9208 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9209 bool isEmpty = necp_addr_is_empty(SA(remote));
9210 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9211 "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9212 0, isEmpty);
9213 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9214 if (isEmpty) {
9215 return FALSE;
9216 }
9217 } else {
9218 if (!isEmpty) {
9219 return FALSE;
9220 }
9221 }
9222 }
9223
9224 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9225 u_int16_t remote_port = 0;
9226 if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9227 remote_port = SIN(remote)->sin_port;
9228 }
9229 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9230 "NECP_KERNEL_CONDITION_SCHEME_PORT",
9231 scheme_port, remote_port);
9232 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9233 if (kernel_policy->cond_scheme_port == scheme_port ||
9234 kernel_policy->cond_scheme_port == remote_port) {
9235 return FALSE;
9236 }
9237 } else {
9238 if (kernel_policy->cond_scheme_port != scheme_port &&
9239 kernel_policy->cond_scheme_port != remote_port) {
9240 return FALSE;
9241 }
9242 }
9243 }
9244
9245 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9246 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9247 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9248 kernel_policy->cond_packet_filter_tags,
9249 pf_tag);
9250 bool tags_matched = false;
9251 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9252 if (pf_tag == PF_TAG_ID_STACK_DROP) {
9253 tags_matched = true;
9254 }
9255 }
9256
9257 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9258 if (tags_matched) {
9259 return FALSE;
9260 }
9261 } else {
9262 if (!tags_matched) {
9263 return FALSE;
9264 }
9265 }
9266 }
9267
9268 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9269 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9270 "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9271 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9272 if (is_loopback) {
9273 return FALSE;
9274 }
9275 } else {
9276 if (!is_loopback) {
9277 return FALSE;
9278 }
9279 }
9280 }
9281
9282 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9283 NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9284 "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9285 if (is_delegated) {
9286 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9287 if (real_is_platform_binary) {
9288 return FALSE;
9289 }
9290 } else {
9291 if (!real_is_platform_binary) {
9292 return FALSE;
9293 }
9294 }
9295 } else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9296 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9297 // If the connection is not delegated, and the policy did not specify a particular effective process UUID
9298 // or PID, check the process directly
9299 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9300 if (is_platform_binary) {
9301 return FALSE;
9302 }
9303 } else {
9304 if (!is_platform_binary) {
9305 return FALSE;
9306 }
9307 }
9308 }
9309 }
9310
9311 return TRUE;
9312 }
9313
9314 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9315 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9316 {
9317 return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9318 }
9319
9320 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,bool override_is_inbound,u_int32_t drop_order,proc_t * socket_proc,struct necp_socket_info * info,bool is_loopback)9321 necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, bool override_is_inbound, u_int32_t drop_order, proc_t *socket_proc, struct necp_socket_info *info, bool is_loopback)
9322 {
9323 struct socket *so = NULL;
9324 proc_t sock_proc = NULL;
9325 proc_t curr_proc = current_proc();
9326
9327 memset(info, 0, sizeof(struct necp_socket_info));
9328
9329 so = inp->inp_socket;
9330
9331 info->drop_order = drop_order;
9332 info->is_loopback = is_loopback;
9333 info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9334
9335 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9336 necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9337 info->uid = kauth_cred_getuid(so->so_cred);
9338 info->real_uid = info->uid;
9339 }
9340
9341 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9342 info->traffic_class = so->so_traffic_class;
9343 }
9344
9345 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9346 info->has_client = !uuid_is_null(inp->necp_client_uuid);
9347 }
9348
9349 if (inp->inp_ip_p) {
9350 info->protocol = inp->inp_ip_p;
9351 } else {
9352 info->protocol = SOCK_PROTO(so);
9353 }
9354
9355 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9356 info->client_flags = 0;
9357 if (INP_NO_CONSTRAINED(inp)) {
9358 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
9359 }
9360 if (INP_NO_EXPENSIVE(inp)) {
9361 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
9362 }
9363 if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
9364 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
9365 }
9366 if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
9367 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
9368 }
9369 if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
9370 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
9371 }
9372 if (inp->inp_socket->so_flags1 & SOF1_INBOUND || ((info->protocol == IPPROTO_UDP) && override_is_inbound)) {
9373 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9374 }
9375 if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
9376 inp->inp_flags2 & INP2_EXTERNAL_PORT) {
9377 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
9378 }
9379 if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
9380 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
9381 }
9382 if (inp->inp_socket->so_options & SO_REUSEPORT) {
9383 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
9384 }
9385 }
9386
9387 if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9388 u_int32_t responsible_application_id = 0;
9389
9390 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9391 if (existing_mapping) {
9392 info->application_id = existing_mapping->id;
9393 }
9394
9395 #if defined(XNU_TARGET_OS_OSX)
9396 if (so->so_rpid > 0) {
9397 existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9398 if (existing_mapping != NULL) {
9399 responsible_application_id = existing_mapping->id;
9400 }
9401 }
9402 #endif
9403
9404 if (responsible_application_id > 0) {
9405 info->real_application_id = info->application_id;
9406 info->application_id = responsible_application_id;
9407 info->used_responsible_pid = true;
9408 } else if (!(so->so_flags & SOF_DELEGATED)) {
9409 info->real_application_id = info->application_id;
9410 } else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9411 struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9412 if (real_existing_mapping) {
9413 info->real_application_id = real_existing_mapping->id;
9414 }
9415 }
9416 }
9417
9418 pid_t socket_pid =
9419 #if defined(XNU_TARGET_OS_OSX)
9420 info->used_responsible_pid ? so->so_rpid :
9421 #endif
9422 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9423 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9424 sock_proc = proc_find(socket_pid);
9425 if (socket_proc) {
9426 *socket_proc = sock_proc;
9427 }
9428 }
9429
9430 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9431 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9432 info->is_entitled = necp_task_has_match_entitlement(task);
9433 if (!info->is_entitled) {
9434 // Task does not have entitlement, check the parent task
9435 necp_get_parent_is_entitled(task, info);
9436 }
9437 }
9438
9439 info->pid = socket_pid;
9440 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9441 info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9442 }
9443
9444 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9445 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9446 if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9447 info->is_platform_binary = true;
9448 } else if (so->so_rpid != 0) {
9449 proc_t responsible_proc = proc_find(so->so_rpid);
9450 if (responsible_proc != NULL) {
9451 if (necp_is_platform_binary(responsible_proc)) {
9452 info->is_platform_binary = true;
9453 info->used_responsible_pid = true;
9454 }
9455 proc_rele(responsible_proc);
9456 }
9457 }
9458 }
9459
9460 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9461 proc_t real_proc = curr_proc;
9462 bool release_real_proc = false;
9463 if (so->last_pid != proc_pid(real_proc)) {
9464 if (so->last_pid == socket_pid && sock_proc != NULL) {
9465 real_proc = sock_proc;
9466 } else {
9467 proc_t last_proc = proc_find(so->last_pid);
9468 if (last_proc != NULL) {
9469 real_proc = last_proc;
9470 release_real_proc = true;
9471 }
9472 }
9473 }
9474 if (real_proc != NULL) {
9475 if (real_proc == kernproc) {
9476 info->real_is_platform_binary = true;
9477 } else {
9478 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9479 }
9480 if (release_real_proc) {
9481 proc_rele(real_proc);
9482 }
9483 }
9484 }
9485
9486 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9487 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9488 if (existing_mapping) {
9489 info->account_id = existing_mapping->id;
9490 }
9491 }
9492
9493 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9494 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9495 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9496 info->domain = inp->inp_necp_attributes.inp_domain;
9497 }
9498
9499 if (override_bound_interface) {
9500 info->bound_interface_index = override_bound_interface;
9501 } else {
9502 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9503 info->bound_interface_index = inp->inp_boundifp->if_index;
9504 }
9505 }
9506
9507 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9508 info->bound_interface_index != IFSCOPE_NONE) {
9509 ifnet_head_lock_shared();
9510 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9511 if (interface != NULL) {
9512 info->bound_interface_flags = interface->if_flags;
9513 info->bound_interface_eflags = interface->if_eflags;
9514 info->bound_interface_xflags = interface->if_xflags;
9515 }
9516 ifnet_head_done();
9517 }
9518
9519 bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9520 uuid_is_null(inp->necp_client_uuid) &&
9521 necp_socket_has_resolver_signature(inp));
9522 if ((necp_data_tracing_level && necp_data_tracing_port) ||
9523 necp_restrict_multicast ||
9524 needs_address_for_signature ||
9525 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
9526 if (override_local_addr != NULL) {
9527 if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9528 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9529 if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9530 struct sockaddr_in sin;
9531 in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9532 memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9533 memcpy(&info->local_addr, &sin, sin.sin_len);
9534 }
9535 } else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9536 SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9537 }
9538 } else {
9539 if (inp->inp_vflag & INP_IPV6) {
9540 SIN6(&info->local_addr)->sin6_family = AF_INET6;
9541 SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9542 SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9543 memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9544 } else if (inp->inp_vflag & INP_IPV4) {
9545 SIN(&info->local_addr)->sin_family = AF_INET;
9546 SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9547 SIN(&info->local_addr)->sin_port = inp->inp_lport;
9548 memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9549 }
9550 }
9551
9552 if (override_remote_addr != NULL) {
9553 if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9554 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9555 if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9556 struct sockaddr_in sin;
9557 in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9558 memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9559 memcpy(&info->remote_addr, &sin, sin.sin_len);
9560 }
9561 } else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9562 SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9563 }
9564 } else {
9565 if (inp->inp_vflag & INP_IPV6) {
9566 SIN6(&info->remote_addr)->sin6_family = AF_INET6;
9567 SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9568 SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
9569 memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
9570 } else if (inp->inp_vflag & INP_IPV4) {
9571 SIN(&info->remote_addr)->sin_family = AF_INET;
9572 SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9573 SIN(&info->remote_addr)->sin_port = inp->inp_fport;
9574 memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
9575 }
9576 }
9577 // Clear the embedded scope id from v6 addresses
9578 if (info->local_addr.sa.sa_family == AF_INET6) {
9579 struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
9580 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9581 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9582 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9583 sin6->sin6_addr.s6_addr16[1] = 0;
9584 }
9585 }
9586 }
9587 if (info->remote_addr.sa.sa_family == AF_INET6) {
9588 struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
9589 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9590 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9591 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9592 sin6->sin6_addr.s6_addr16[1] = 0;
9593 }
9594 }
9595 }
9596 }
9597
9598 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9599 // For checking sockets, only validate that there is an NECP client present. It will have
9600 // already checked for the signature.
9601 if (!uuid_is_null(inp->necp_client_uuid)) {
9602 info->has_system_signed_result = true;
9603 } else {
9604 info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
9605 }
9606 }
9607 }
9608
9609 #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)
9610
9611 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)9612 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
9613 struct necp_socket_info *info,
9614 necp_kernel_policy_filter *return_filter,
9615 u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
9616 size_t *return_route_rule_id_array_count,
9617 size_t route_rule_id_array_count,
9618 necp_kernel_policy_result *return_service_action,
9619 necp_kernel_policy_service *return_service,
9620 u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
9621 size_t netagent_array_count,
9622 u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
9623 size_t netagent_use_flags_array_count,
9624 struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9625 u_int32_t num_required_agent_types,
9626 proc_t proc,
9627 u_int16_t pf_tag,
9628 necp_kernel_policy_id *skip_policy_id,
9629 struct rtentry *rt,
9630 necp_kernel_policy_result *return_drop_dest_policy_result,
9631 necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
9632 u_int32_t *return_flow_divert_aggregate_unit,
9633 struct socket *so,
9634 int debug)
9635 {
9636 struct necp_kernel_socket_policy *matched_policy = NULL;
9637 u_int32_t skip_order = 0;
9638 u_int32_t skip_session_order = 0;
9639 bool skipped_ip_result = false;
9640 size_t route_rule_id_count = 0;
9641 int i;
9642 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
9643 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
9644 memset(&netagent_ids, 0, sizeof(netagent_ids));
9645 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
9646 size_t netagent_cursor = 0;
9647 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9648 size_t netagent_array_count_adjusted = netagent_array_count;
9649 if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
9650 netagent_array_count_adjusted = netagent_use_flags_array_count;
9651 }
9652
9653 if (return_drop_all_bypass != NULL) {
9654 *return_drop_all_bypass = drop_all_bypass;
9655 }
9656
9657 if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
9658 netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
9659 }
9660
9661 // Pre-process domain for quick matching
9662 struct substring domain_substring = {};
9663 u_int8_t domain_dot_count = 0;
9664 if (info->domain != NULL) {
9665 domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
9666 domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
9667 }
9668
9669 if (return_filter != NULL) {
9670 *return_filter = 0;
9671 }
9672
9673 if (return_route_rule_id_array_count != NULL) {
9674 *return_route_rule_id_array_count = 0;
9675 }
9676
9677 if (return_service_action != NULL) {
9678 *return_service_action = 0;
9679 }
9680
9681 if (return_service != NULL) {
9682 return_service->identifier = 0;
9683 return_service->data = 0;
9684 }
9685
9686 // Do not subject layer-2 filter to NECP policies, return a PASS policy
9687 if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
9688 return &pass_policy;
9689 }
9690
9691 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9692
9693 if (policy_search_array != NULL) {
9694 for (i = 0; policy_search_array[i] != NULL; i++) {
9695 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
9696
9697 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
9698 // We've hit a drop all rule
9699 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
9700 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
9701 if (return_drop_all_bypass != NULL) {
9702 *return_drop_all_bypass = drop_all_bypass;
9703 }
9704 }
9705 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
9706 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
9707 break;
9708 }
9709 }
9710 if (necp_drop_dest_policy.entry_count != 0 &&
9711 necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
9712 // We've hit a drop by destination address rule
9713 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
9714 break;
9715 }
9716 if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
9717 // We've hit a drop order for this socket
9718 break;
9719 }
9720 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
9721 // Done skipping
9722 skip_order = 0;
9723 skip_session_order = 0;
9724 // If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
9725 if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
9726 *skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9727 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
9728 }
9729 }
9730 if (skip_order) {
9731 if (policy_search_array[i]->order < skip_order) {
9732 // Skip this policy
9733 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
9734 // didn't, clear out the return value for skip ID when we are done with each session.'
9735 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
9736 skipped_ip_result = true;
9737 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
9738 }
9739 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
9740 continue;
9741 } else {
9742 // Done skipping
9743 skip_order = 0;
9744 skip_session_order = 0;
9745 }
9746 } else if (skip_session_order) {
9747 // Skip this policy
9748 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
9749 // didn't, clear out the return value for skip ID when we are done with each session.'
9750 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
9751 skipped_ip_result = true;
9752 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
9753 }
9754 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
9755 continue;
9756 }
9757
9758 if (necp_socket_check_policy(policy_search_array[i],
9759 info->application_id,
9760 info->real_application_id,
9761 info->is_entitled,
9762 info->account_id,
9763 domain_substring,
9764 domain_dot_count,
9765 info->url,
9766 info->pid,
9767 info->pid_version,
9768 info->uid,
9769 info->real_uid,
9770 info->bound_interface_index,
9771 info->traffic_class,
9772 info->protocol,
9773 &info->local_addr,
9774 &info->remote_addr,
9775 required_agent_types,
9776 num_required_agent_types,
9777 info->has_client,
9778 info->client_flags,
9779 info->is_platform_binary,
9780 info->has_system_signed_result,
9781 proc,
9782 pf_tag,
9783 info->scheme_port,
9784 rt,
9785 info->is_loopback,
9786 debug,
9787 info->real_is_platform_binary,
9788 info->bound_interface_flags,
9789 info->bound_interface_eflags,
9790 info->bound_interface_xflags,
9791 info,
9792 info->is_delegated,
9793 so)) {
9794 if (!debug && necp_data_tracing_session_order) {
9795 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
9796 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
9797 NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
9798 }
9799 }
9800
9801 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
9802 if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
9803 necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
9804 if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
9805 *return_filter = control_unit;
9806 } else {
9807 // Preserve pre-existing connections only if all filters preserve.
9808 bool preserve_bit_off = false;
9809 if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
9810 (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
9811 preserve_bit_off = true;
9812 }
9813 *return_filter |= control_unit;
9814 if (preserve_bit_off == true) {
9815 *return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
9816 }
9817 }
9818 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9819 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);
9820 }
9821 }
9822 continue;
9823 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
9824 if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
9825 return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
9826 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9827 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);
9828 }
9829 }
9830 continue;
9831 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
9832 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9833 if (netagent_cursor < netagent_array_count_adjusted) {
9834 bool agent_already_present = false;
9835 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
9836 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
9837 // Already present. Mark the "SCOPED" flag if flags are necessary.
9838 agent_already_present = true;
9839 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
9840 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9841 netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
9842 }
9843 }
9844 }
9845
9846 if (!agent_already_present) {
9847 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
9848 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9849 netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
9850 }
9851 netagent_cursor++;
9852 }
9853 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9854 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
9855 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
9856 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
9857 policy_search_array[i]->result_parameter.netagent_id);
9858 }
9859 }
9860 continue;
9861 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
9862 bool agent_already_present = false;
9863 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
9864 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
9865 // Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
9866 agent_already_present = true;
9867 netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
9868 }
9869 }
9870 if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
9871 // If not present, and flags are supported, add an entry with the "REMOVE" flag
9872 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
9873 netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
9874 netagent_cursor++;
9875 }
9876 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9877 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
9878 (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
9879 policy_search_array[i]->result_parameter.netagent_id);
9880 }
9881 continue;
9882 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
9883 u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
9884 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
9885 /* For transparent proxies, accumulate the control unit and continue to the next policy */
9886 if (return_flow_divert_aggregate_unit != NULL) {
9887 *return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
9888 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9889 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);
9890 }
9891 }
9892 continue;
9893 }
9894 }
9895
9896 // Matched policy is a skip. Do skip and continue.
9897 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
9898 NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
9899 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
9900 skip_session_order = policy_search_array[i]->session_order + 1;
9901 if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
9902 *skip_policy_id = policy_search_array[i]->id;
9903 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9904 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);
9905 }
9906 }
9907 continue;
9908 }
9909
9910 // Matched an allow unentitled, which clears any drop order
9911 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
9912 info->drop_order = 0;
9913 continue;
9914 }
9915
9916 // Passed all tests, found a match
9917 matched_policy = policy_search_array[i];
9918 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
9919 break;
9920 }
9921 }
9922 }
9923
9924 if (return_netagent_array != NULL) {
9925 if (return_netagent_use_flags_array != NULL) {
9926 memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
9927 memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
9928 } else {
9929 for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
9930 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
9931 return_netagent_array[netagent_i] = netagent_ids[netagent_i];
9932 } else {
9933 return_netagent_array[netagent_i] = 0;
9934 }
9935 }
9936 }
9937 }
9938
9939 if (return_route_rule_id_array_count != NULL) {
9940 *return_route_rule_id_array_count = route_rule_id_count;
9941 }
9942 return matched_policy;
9943 }
9944
9945 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)9946 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
9947 {
9948 bool found_match = FALSE;
9949 ifaddr_t ifa;
9950 union necp_sockaddr_union address_storage;
9951 int family = AF_INET;
9952
9953 ifnet_head_lock_shared();
9954 ifnet_t interface = ifindex2ifnet[interface_index];
9955 ifnet_head_done();
9956
9957 if (inp == NULL || interface == NULL) {
9958 return FALSE;
9959 }
9960
9961 if (inp->inp_vflag & INP_IPV4) {
9962 family = AF_INET;
9963 } else if (inp->inp_vflag & INP_IPV6) {
9964 family = AF_INET6;
9965 } else {
9966 return FALSE;
9967 }
9968
9969 // Match socket address against interface addresses
9970 ifnet_lock_shared(interface);
9971 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
9972 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
9973 if (address_storage.sa.sa_family != family) {
9974 continue;
9975 }
9976
9977 if (family == AF_INET) {
9978 if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
9979 found_match = TRUE;
9980 break;
9981 }
9982 } else if (family == AF_INET6) {
9983 if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
9984 found_match = TRUE;
9985 break;
9986 }
9987 }
9988 }
9989 }
9990 ifnet_lock_done(interface);
9991
9992 return found_match;
9993 }
9994
9995 static inline bool
necp_socket_is_connected(struct inpcb * inp)9996 necp_socket_is_connected(struct inpcb *inp)
9997 {
9998 return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
9999 }
10000
10001 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10002 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10003 {
10004 if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10005 proc_t curr_proc = current_proc();
10006 proc_t sock_proc = NULL;
10007 struct socket *so = inp ? inp->inp_socket : NULL;
10008 pid_t socket_pid = (so == NULL) ? 0 :
10009 #if defined(XNU_TARGET_OS_OSX)
10010 so->so_rpid ? so->so_rpid :
10011 #endif
10012 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10013 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10014 sock_proc = proc_find(socket_pid);
10015 }
10016 const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10017 if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10018 if (sock_proc) {
10019 proc_rele(sock_proc);
10020 }
10021 return NECP_BYPASS_TYPE_DROP;
10022 }
10023 if (sock_proc) {
10024 proc_rele(sock_proc);
10025 }
10026
10027 if (necp_pass_loopback > 0) {
10028 return NECP_BYPASS_TYPE_LOOPBACK;
10029 }
10030 } else if (necp_is_intcoproc(inp, NULL)) {
10031 return NECP_BYPASS_TYPE_INTCOPROC;
10032 }
10033
10034 return NECP_BYPASS_TYPE_NONE;
10035 }
10036
10037 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10038 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10039 {
10040 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10041 ifnet_t tunnel_interface = NULL;
10042
10043 ifnet_head_lock_shared();
10044 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10045 ifnet_head_done();
10046
10047 if (tunnel_interface != NULL) {
10048 tcp_set_tso(intotcpcb(inp), tunnel_interface);
10049 }
10050 }
10051
10052 static inline void
necp_unscope(struct inpcb * inp)10053 necp_unscope(struct inpcb *inp)
10054 {
10055 // If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10056 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10057 inp->inp_flags &= ~INP_BOUND_IF;
10058 inp->inp_boundifp = NULL;
10059 }
10060 }
10061
10062 static inline void
necp_clear_tunnel(struct inpcb * inp)10063 necp_clear_tunnel(struct inpcb *inp)
10064 {
10065 if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10066 inp->inp_flags &= ~INP_BOUND_IF;
10067 inp->inp_boundifp = NULL;
10068 }
10069 }
10070
10071 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10072 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10073 {
10074 // Verify netagents
10075 for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10076 struct necp_uuid_id_mapping *mapping = NULL;
10077 u_int32_t netagent_id = netagent_ids[netagent_cursor];
10078 if (netagent_id == 0) {
10079 continue;
10080 }
10081 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
10082 if (mapping != NULL) {
10083 u_int32_t agent_flags = 0;
10084 agent_flags = netagent_get_flags(mapping->uuid);
10085 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10086 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10087 continue;
10088 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10089 if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10090 int trigger_error = 0;
10091 trigger_error = netagent_kernel_trigger(mapping->uuid);
10092 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10093 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);
10094 }
10095 }
10096 return false;
10097 }
10098 }
10099 }
10100 }
10101 return true;
10102 }
10103
10104 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)10105 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10106 {
10107 struct socket *so = NULL;
10108 necp_kernel_policy_filter filter_control_unit = 0;
10109 struct necp_kernel_socket_policy *matched_policy = NULL;
10110 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10111 necp_kernel_policy_result service_action = 0;
10112 necp_kernel_policy_service service = { 0, 0 };
10113 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10114 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10115 proc_t __single socket_proc = NULL;
10116 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10117
10118 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10119 memset(&netagent_ids, 0, sizeof(netagent_ids));
10120
10121 struct necp_socket_info info = {};
10122
10123 u_int32_t flow_divert_aggregate_unit = 0;
10124
10125 if (inp == NULL) {
10126 return NECP_KERNEL_POLICY_ID_NONE;
10127 }
10128
10129 // Ignore invalid addresses
10130 if (override_local_addr != NULL &&
10131 !necp_address_is_valid(override_local_addr)) {
10132 override_local_addr = NULL;
10133 }
10134 if (override_remote_addr != NULL &&
10135 !necp_address_is_valid(override_remote_addr)) {
10136 override_remote_addr = NULL;
10137 }
10138
10139 so = inp->inp_socket;
10140
10141 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10142
10143 // Don't lock. Possible race condition, but we don't want the performance hit.
10144 if (necp_drop_management_order == 0 &&
10145 (necp_kernel_socket_policies_count == 0 ||
10146 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10147 if (necp_drop_all_order > 0 || drop_order > 0) {
10148 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10149 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10150 inp->inp_policyresult.policy_gencount = 0;
10151 inp->inp_policyresult.app_id = 0;
10152 inp->inp_policyresult.flowhash = 0;
10153 inp->inp_policyresult.results.filter_control_unit = 0;
10154 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10155 inp->inp_policyresult.results.route_rule_id = 0;
10156 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10157 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10158 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10159 } else {
10160 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10161 }
10162 }
10163 return NECP_KERNEL_POLICY_ID_NONE;
10164 }
10165
10166 // Check for loopback exception
10167 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10168 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10169 // Mark socket as a drop
10170 necp_unscope(inp);
10171 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10172 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10173 inp->inp_policyresult.policy_gencount = 0;
10174 inp->inp_policyresult.app_id = 0;
10175 inp->inp_policyresult.flowhash = 0;
10176 inp->inp_policyresult.results.filter_control_unit = 0;
10177 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10178 inp->inp_policyresult.results.route_rule_id = 0;
10179 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10180 return NECP_KERNEL_POLICY_ID_NONE;
10181 }
10182
10183 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10184 // Mark socket as a pass
10185 necp_unscope(inp);
10186 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10187 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10188 inp->inp_policyresult.policy_gencount = 0;
10189 inp->inp_policyresult.app_id = 0;
10190 inp->inp_policyresult.flowhash = 0;
10191 inp->inp_policyresult.results.filter_control_unit = 0;
10192 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10193 inp->inp_policyresult.results.route_rule_id = 0;
10194 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10195 return NECP_KERNEL_POLICY_ID_NONE;
10196 }
10197
10198 // Lock
10199 lck_rw_lock_shared(&necp_kernel_policy_lock);
10200 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, false, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
10201
10202 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10203 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10204
10205 // Check info
10206 u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10207 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10208 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10209 inp->inp_policyresult.flowhash == flowhash) {
10210 // If already matched this socket on this generation of table, skip
10211
10212 // Unlock
10213 lck_rw_done(&necp_kernel_policy_lock);
10214
10215 if (socket_proc) {
10216 proc_rele(socket_proc);
10217 }
10218
10219 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10220 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10221 inp->inp_socket, info.bound_interface_index, info.protocol,
10222 inp->inp_policyresult.policy_id,
10223 inp->inp_policyresult.results.result,
10224 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10225 }
10226 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10227 return inp->inp_policyresult.policy_id;
10228 }
10229
10230 inp->inp_policyresult.app_id = info.application_id;
10231
10232 // Match socket to policy
10233 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10234 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10235 size_t route_rule_id_array_count = 0;
10236
10237 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10238 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)],
10239 &info,
10240 &filter_control_unit,
10241 route_rule_id_array,
10242 &route_rule_id_array_count,
10243 MAX_AGGREGATE_ROUTE_RULES,
10244 &service_action,
10245 &service,
10246 netagent_ids,
10247 NECP_MAX_NETAGENTS,
10248 NULL,
10249 0,
10250 NULL,
10251 0,
10252 effective_proc,
10253 0,
10254 &skip_policy_id,
10255 inp->inp_route.ro_rt,
10256 &drop_dest_policy_result,
10257 &drop_all_bypass,
10258 &flow_divert_aggregate_unit,
10259 so,
10260 debug);
10261
10262 // Check for loopback exception again after the policy match
10263 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10264 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10265 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10266 // Mark socket as a pass
10267 necp_unscope(inp);
10268 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10269 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10270 inp->inp_policyresult.policy_gencount = 0;
10271 inp->inp_policyresult.app_id = 0;
10272 inp->inp_policyresult.flowhash = 0;
10273 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10274 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10275 inp->inp_policyresult.results.route_rule_id = 0;
10276 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10277
10278 // Unlock
10279 lck_rw_done(&necp_kernel_policy_lock);
10280
10281 if (socket_proc) {
10282 proc_rele(socket_proc);
10283 }
10284
10285 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10286 return NECP_KERNEL_POLICY_ID_NONE;
10287 }
10288
10289 // Verify netagents
10290 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10291 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10292 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);
10293 }
10294
10295 // Mark socket as a drop if required agent is not active
10296 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10297 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10298 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10299 inp->inp_policyresult.flowhash = flowhash;
10300 inp->inp_policyresult.results.filter_control_unit = 0;
10301 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10302 inp->inp_policyresult.results.route_rule_id = 0;
10303 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10304
10305 // Unlock
10306 lck_rw_done(&necp_kernel_policy_lock);
10307
10308 if (socket_proc) {
10309 proc_rele(socket_proc);
10310 }
10311
10312 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);
10313 return NECP_KERNEL_POLICY_ID_NONE;
10314 }
10315
10316 u_int32_t route_rule_id = 0;
10317 if (route_rule_id_array_count == 1) {
10318 route_rule_id = route_rule_id_array[0];
10319 } else if (route_rule_id_array_count > 1) {
10320 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10321 }
10322
10323 bool reset_tcp_tunnel_interface = false;
10324 bool send_local_network_denied_event = false;
10325 if (matched_policy) {
10326 // For PASS policy result, clear previous rescope / tunnel inteface
10327 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10328 (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10329 necp_unscope(inp);
10330 necp_clear_tunnel(inp);
10331 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10332 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10333 }
10334 }
10335 matched_policy_id = matched_policy->id;
10336 inp->inp_policyresult.policy_id = matched_policy->id;
10337 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10338 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10339 inp->inp_policyresult.flowhash = flowhash;
10340 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10341 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10342 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10343 inp->inp_policyresult.results.result = matched_policy->result;
10344 memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10345
10346 if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10347 inp->inp_policyresult.app_id = info.real_application_id;
10348 }
10349
10350 if (necp_socket_is_connected(inp) &&
10351 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10352 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10353 NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10354 sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10355 } else if (necp_socket_is_connected(inp) &&
10356 matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10357 info.protocol == IPPROTO_TCP) {
10358 // Reset TCP socket interface based parameters if tunnel policy changes
10359 reset_tcp_tunnel_interface = true;
10360 }
10361
10362 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10363 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);
10364 }
10365
10366 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10367 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10368 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10369 // Trigger the event that we dropped due to a local network policy
10370 send_local_network_denied_event = true;
10371 }
10372 } else {
10373 bool drop_all = false;
10374 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10375 // Mark socket as a drop if set
10376 drop_all = true;
10377 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10378 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10379 }
10380 }
10381
10382 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10383 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);
10384 if (flow_divert_control_unit != 0) {
10385 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10386 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10387 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10388 inp->inp_policyresult.flowhash = flowhash;
10389 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10390 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10391 inp->inp_policyresult.results.route_rule_id = route_rule_id;
10392 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10393 inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10394 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);
10395 } else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10396 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10397 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10398 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10399 inp->inp_policyresult.flowhash = flowhash;
10400 inp->inp_policyresult.results.filter_control_unit = 0;
10401 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10402 inp->inp_policyresult.results.route_rule_id = 0;
10403 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10404 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);
10405 } else {
10406 // Mark non-matching socket so we don't re-check it
10407 necp_unscope(inp);
10408 if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10409 necp_clear_tunnel(inp);
10410 }
10411 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10412 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);
10413 }
10414 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10415 inp->inp_policyresult.skip_policy_id = skip_policy_id;
10416 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10417 inp->inp_policyresult.flowhash = flowhash;
10418 inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10419 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10420 inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10421 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10422 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10423 }
10424 }
10425
10426 if (necp_check_missing_client_drop(effective_proc, &info) ||
10427 necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10428 // Mark as drop
10429 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10430 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10431 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10432 inp->inp_policyresult.flowhash = flowhash;
10433 inp->inp_policyresult.results.filter_control_unit = 0;
10434 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10435 inp->inp_policyresult.results.route_rule_id = 0;
10436 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10437 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10438 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10439 }
10440 }
10441
10442 // Unlock
10443 lck_rw_done(&necp_kernel_policy_lock);
10444
10445 if (reset_tcp_tunnel_interface) {
10446 // Update MSS when not holding the policy lock to avoid recursive locking
10447 tcp_mtudisc(inp, 0);
10448
10449 // Update TSO flag based on the tunnel interface
10450 necp_socket_ip_tunnel_tso(inp);
10451 }
10452
10453 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10454 inp->inp_policyresult.network_denied_notifies++;
10455 #if defined(XNU_TARGET_OS_OSX)
10456 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10457 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10458 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10459 NETPOLICY_NETWORKTYPE_LOCAL);
10460 #else
10461 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10462 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10463 NETPOLICY_NETWORKTYPE_LOCAL);
10464 #endif
10465 }
10466
10467 if (socket_proc) {
10468 proc_rele(socket_proc);
10469 }
10470
10471 return matched_policy_id;
10472 }
10473
10474 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)10475 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)
10476 {
10477 u_int32_t bound_interface_flags = 0;
10478 u_int32_t bound_interface_eflags = 0;
10479 u_int32_t bound_interface_xflags = 0;
10480
10481 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
10482 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10483 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
10484 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
10485 "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
10486 cond_bound_interface_index, bound_interface_index);
10487 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10488 if (bound_interface_index == cond_bound_interface_index) {
10489 // No match, matches forbidden interface
10490 return FALSE;
10491 }
10492 } else {
10493 if (bound_interface_index != cond_bound_interface_index) {
10494 // No match, does not match required interface
10495 return FALSE;
10496 }
10497 }
10498 }
10499 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10500 if (bound_interface_index != IFSCOPE_NONE) {
10501 ifnet_head_lock_shared();
10502 ifnet_t interface = ifindex2ifnet[bound_interface_index];
10503 if (interface != NULL) {
10504 bound_interface_flags = interface->if_flags;
10505 bound_interface_eflags = interface->if_eflags;
10506 bound_interface_xflags = interface->if_xflags;
10507 }
10508 ifnet_head_done();
10509 }
10510
10511 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10512 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
10513 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10514 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
10515 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10516 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
10517 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10518 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10519 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10520 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10521 // No match, matches some forbidden interface flags
10522 return FALSE;
10523 }
10524 } else {
10525 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10526 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10527 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10528 // No match, does not match some required interface xflags
10529 return FALSE;
10530 }
10531 }
10532 }
10533 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
10534 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
10535 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
10536 if (bound_interface_index != 0) {
10537 // No match, requires a non-bound packet
10538 return FALSE;
10539 }
10540 }
10541 }
10542
10543 if (kernel_policy->condition_mask == 0) {
10544 return TRUE;
10545 }
10546
10547 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10548 necp_kernel_policy_id matched_policy_id =
10549 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10550 NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
10551 "NECP_KERNEL_CONDITION_POLICY_ID",
10552 kernel_policy->cond_policy_id, 0, 0,
10553 matched_policy_id, socket_policy_id, socket_skip_policy_id);
10554 if (matched_policy_id != kernel_policy->cond_policy_id) {
10555 // No match, does not match required id
10556 return FALSE;
10557 }
10558 }
10559
10560 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10561 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
10562 "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10563 kernel_policy->cond_last_interface_index, last_interface_index);
10564 if (last_interface_index != kernel_policy->cond_last_interface_index) {
10565 return FALSE;
10566 }
10567 }
10568
10569 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10570 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
10571 "NECP_KERNEL_CONDITION_PROTOCOL",
10572 kernel_policy->cond_protocol, protocol);
10573 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10574 if (protocol == kernel_policy->cond_protocol) {
10575 // No match, matches forbidden protocol
10576 return FALSE;
10577 }
10578 } else {
10579 if (protocol != kernel_policy->cond_protocol) {
10580 // No match, does not match required protocol
10581 return FALSE;
10582 }
10583 }
10584 }
10585
10586 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10587 bool is_local = FALSE;
10588 bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
10589
10590 if (rt != NULL) {
10591 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
10592 } else {
10593 is_local = necp_is_route_local(remote, include_local_addresses);
10594 }
10595 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);
10596 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10597 if (is_local) {
10598 // Match local-networks, fail
10599 return FALSE;
10600 }
10601 } else {
10602 if (!is_local) {
10603 // Either no route to validate or no match for local networks
10604 return FALSE;
10605 }
10606 }
10607 }
10608
10609 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
10610 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10611 bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
10612 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
10613 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10614 if (inRange) {
10615 return FALSE;
10616 }
10617 } else {
10618 if (!inRange) {
10619 return FALSE;
10620 }
10621 }
10622 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10623 bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
10624 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
10625 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10626 if (inSubnet) {
10627 return FALSE;
10628 }
10629 } else {
10630 if (!inSubnet) {
10631 return FALSE;
10632 }
10633 }
10634 }
10635 }
10636
10637 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
10638 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
10639 bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
10640 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
10641 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
10642 if (inRange) {
10643 return FALSE;
10644 }
10645 } else {
10646 if (!inRange) {
10647 return FALSE;
10648 }
10649 }
10650 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
10651 bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
10652 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
10653 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
10654 if (inSubnet) {
10655 return FALSE;
10656 }
10657 } else {
10658 if (!inSubnet) {
10659 return FALSE;
10660 }
10661 }
10662 }
10663 }
10664
10665 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
10666 u_int16_t remote_port = 0;
10667 if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
10668 remote_port = SIN(remote)->sin_port;
10669 }
10670 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
10671 "NECP_KERNEL_CONDITION_SCHEME_PORT",
10672 0, remote_port);
10673 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
10674 if (kernel_policy->cond_scheme_port == remote_port) {
10675 return FALSE;
10676 }
10677 } else {
10678 if (kernel_policy->cond_scheme_port != remote_port) {
10679 return FALSE;
10680 }
10681 }
10682 }
10683
10684 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
10685 bool tags_matched = false;
10686 NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
10687 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
10688 kernel_policy->cond_packet_filter_tags, pf_tag);
10689 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
10690 if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
10691 tags_matched = true;
10692 }
10693
10694 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
10695 if (tags_matched) {
10696 return FALSE;
10697 }
10698 } else {
10699 if (!tags_matched) {
10700 return FALSE;
10701 }
10702 }
10703 }
10704 }
10705
10706 return TRUE;
10707 }
10708
10709 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)10710 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)
10711 {
10712 u_int32_t skip_order = 0;
10713 u_int32_t skip_session_order = 0;
10714 struct necp_kernel_ip_output_policy *matched_policy = NULL;
10715 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)];
10716 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
10717 size_t route_rule_id_count = 0;
10718 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10719 if (return_drop_all_bypass != NULL) {
10720 *return_drop_all_bypass = drop_all_bypass;
10721 }
10722
10723 if (return_route_rule_id != NULL) {
10724 *return_route_rule_id = 0;
10725 }
10726
10727 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10728
10729 if (policy_search_array != NULL) {
10730 for (int i = 0; policy_search_array[i] != NULL; i++) {
10731 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
10732 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10733 // We've hit a drop all rule
10734 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10735 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10736 if (return_drop_all_bypass != NULL) {
10737 *return_drop_all_bypass = drop_all_bypass;
10738 }
10739 }
10740 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10741 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
10742 break;
10743 }
10744 }
10745 if (necp_drop_dest_policy.entry_count > 0 &&
10746 necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
10747 // We've hit a drop by destination address rule
10748 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10749 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
10750 break;
10751 }
10752 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10753 // Done skipping
10754 skip_order = 0;
10755 skip_session_order = 0;
10756 }
10757 if (skip_order) {
10758 if (policy_search_array[i]->order < skip_order) {
10759 // Skip this policy
10760 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
10761 continue;
10762 } else {
10763 // Done skipping
10764 skip_order = 0;
10765 skip_session_order = 0;
10766 }
10767 } else if (skip_session_order) {
10768 // Skip this policy
10769 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
10770 continue;
10771 }
10772
10773 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)) {
10774 if (!debug && necp_data_tracing_session_order) {
10775 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10776 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10777 NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
10778 }
10779 }
10780
10781 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10782 if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
10783 route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10784 }
10785 continue;
10786 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10787 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10788 skip_session_order = policy_search_array[i]->session_order + 1;
10789 NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
10790 continue;
10791 }
10792
10793 // Passed all tests, found a match
10794 matched_policy = policy_search_array[i];
10795 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
10796 break;
10797 }
10798 }
10799 }
10800
10801 if (route_rule_id_count == 1) {
10802 *return_route_rule_id = route_rule_id_array[0];
10803 } else if (route_rule_id_count > 1) {
10804 *return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10805 }
10806
10807 return matched_policy;
10808 }
10809
10810 static inline bool
necp_output_bypass(struct mbuf * packet)10811 necp_output_bypass(struct mbuf *packet)
10812 {
10813 if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
10814 return true;
10815 }
10816 if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
10817 return true;
10818 }
10819 if (necp_is_intcoproc(NULL, packet)) {
10820 return true;
10821 }
10822 return false;
10823 }
10824
10825 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)10826 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
10827 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
10828 {
10829 struct ip *ip = NULL;
10830 int hlen = sizeof(struct ip);
10831 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10832 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10833 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10834 struct necp_kernel_ip_output_policy *matched_policy = NULL;
10835 u_int16_t protocol = 0;
10836 u_int32_t bound_interface_index = 0;
10837 u_int32_t last_interface_index = 0;
10838 union necp_sockaddr_union local_addr = { };
10839 union necp_sockaddr_union remote_addr = { };
10840 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10841 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10842 u_int16_t pf_tag = 0;
10843
10844 if (result) {
10845 *result = 0;
10846 }
10847
10848 if (result_parameter) {
10849 memset(result_parameter, 0, sizeof(*result_parameter));
10850 }
10851
10852 if (packet == NULL) {
10853 return NECP_KERNEL_POLICY_ID_NONE;
10854 }
10855
10856 socket_policy_id = necp_get_policy_id_from_packet(packet);
10857 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
10858 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
10859
10860 // Exit early for an empty list
10861 // Don't lock. Possible race condition, but we don't want the performance hit.
10862 if (necp_kernel_ip_output_policies_count == 0 ||
10863 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
10864 if (necp_drop_all_order > 0) {
10865 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10866 if (result) {
10867 if (necp_output_bypass(packet)) {
10868 *result = NECP_KERNEL_POLICY_RESULT_PASS;
10869 } else {
10870 *result = NECP_KERNEL_POLICY_RESULT_DROP;
10871 }
10872 }
10873 }
10874
10875 return matched_policy_id;
10876 }
10877
10878 // Check for loopback exception
10879 if (necp_output_bypass(packet)) {
10880 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10881 if (result) {
10882 *result = NECP_KERNEL_POLICY_RESULT_PASS;
10883 }
10884 return matched_policy_id;
10885 }
10886
10887 last_interface_index = necp_get_last_interface_index_from_packet(packet);
10888
10889 // Process packet to get relevant fields
10890 ip = mtod(packet, struct ip *);
10891 #ifdef _IP_VHL
10892 hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
10893 #else
10894 hlen = ip->ip_hl << 2;
10895 #endif
10896
10897 protocol = ip->ip_p;
10898
10899 if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
10900 (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
10901 ipoa->ipoa_boundif != IFSCOPE_NONE) {
10902 bound_interface_index = ipoa->ipoa_boundif;
10903 }
10904
10905 local_addr.sin.sin_family = AF_INET;
10906 local_addr.sin.sin_len = sizeof(struct sockaddr_in);
10907 memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
10908
10909 remote_addr.sin.sin_family = AF_INET;
10910 remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
10911 memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
10912
10913 switch (protocol) {
10914 case IPPROTO_TCP: {
10915 struct tcphdr th;
10916 if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
10917 m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
10918 SIN(&local_addr)->sin_port = th.th_sport;
10919 SIN(&remote_addr)->sin_port = th.th_dport;
10920 }
10921 break;
10922 }
10923 case IPPROTO_UDP: {
10924 struct udphdr uh;
10925 if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
10926 m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
10927 SIN(&local_addr)->sin_port = uh.uh_sport;
10928 SIN(&remote_addr)->sin_port = uh.uh_dport;
10929 }
10930 break;
10931 }
10932 default: {
10933 SIN(&local_addr)->sin_port = 0;
10934 SIN(&remote_addr)->sin_port = 0;
10935 break;
10936 }
10937 }
10938
10939 // Match packet to policy
10940 lck_rw_lock_shared(&necp_kernel_policy_lock);
10941 u_int32_t route_rule_id = 0;
10942
10943 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
10944 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
10945
10946 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);
10947 if (matched_policy) {
10948 matched_policy_id = matched_policy->id;
10949 if (result) {
10950 *result = matched_policy->result;
10951 }
10952
10953 if (result_parameter) {
10954 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10955 }
10956
10957 if (route_rule_id != 0 &&
10958 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10959 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10960 }
10961
10962 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10963 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);
10964 }
10965 } else {
10966 bool drop_all = false;
10967 /*
10968 * Apply drop-all only to packets which have never matched a primary policy (check
10969 * if the packet saved policy id is none or falls within the socket policy id range).
10970 */
10971 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
10972 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
10973 drop_all = true;
10974 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10975 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10976 }
10977 }
10978 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10979 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10980 if (result) {
10981 *result = NECP_KERNEL_POLICY_RESULT_DROP;
10982 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
10983 }
10984 } else if (route_rule_id != 0 &&
10985 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10986 // If we matched a route rule, mark it
10987 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10988 }
10989 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10990 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);
10991 }
10992 }
10993
10994 lck_rw_done(&necp_kernel_policy_lock);
10995
10996 return matched_policy_id;
10997 }
10998
10999 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)11000 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11001 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11002 {
11003 struct ip6_hdr *ip6 = NULL;
11004 int next = -1;
11005 int offset = 0;
11006 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11007 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11008 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11009 struct necp_kernel_ip_output_policy *matched_policy = NULL;
11010 u_int16_t protocol = 0;
11011 u_int32_t bound_interface_index = 0;
11012 u_int32_t last_interface_index = 0;
11013 union necp_sockaddr_union local_addr = { };
11014 union necp_sockaddr_union remote_addr = { };
11015 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11016 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11017 u_int16_t pf_tag = 0;
11018
11019 if (result) {
11020 *result = 0;
11021 }
11022
11023 if (result_parameter) {
11024 memset(result_parameter, 0, sizeof(*result_parameter));
11025 }
11026
11027 if (packet == NULL) {
11028 return NECP_KERNEL_POLICY_ID_NONE;
11029 }
11030
11031 socket_policy_id = necp_get_policy_id_from_packet(packet);
11032 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11033 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11034
11035 // Exit early for an empty list
11036 // Don't lock. Possible race condition, but we don't want the performance hit.
11037 if (necp_drop_management_order == 0 &&
11038 (necp_kernel_ip_output_policies_count == 0 ||
11039 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11040 if (necp_drop_all_order > 0) {
11041 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11042 if (result) {
11043 if (necp_output_bypass(packet)) {
11044 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11045 } else {
11046 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11047 }
11048 }
11049 }
11050
11051 return matched_policy_id;
11052 }
11053
11054 // Check for loopback exception
11055 if (necp_output_bypass(packet)) {
11056 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11057 if (result) {
11058 *result = NECP_KERNEL_POLICY_RESULT_PASS;
11059 }
11060 return matched_policy_id;
11061 }
11062
11063 last_interface_index = necp_get_last_interface_index_from_packet(packet);
11064
11065 // Process packet to get relevant fields
11066 ip6 = mtod(packet, struct ip6_hdr *);
11067
11068 if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11069 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11070 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11071 bound_interface_index = ip6oa->ip6oa_boundif;
11072 }
11073
11074 SIN6(&local_addr)->sin6_family = AF_INET6;
11075 SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11076 memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11077
11078 SIN6(&remote_addr)->sin6_family = AF_INET6;
11079 SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11080 memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11081
11082 offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11083 if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11084 protocol = next;
11085 switch (protocol) {
11086 case IPPROTO_TCP: {
11087 struct tcphdr th;
11088 if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11089 m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11090 SIN6(&local_addr)->sin6_port = th.th_sport;
11091 SIN6(&remote_addr)->sin6_port = th.th_dport;
11092 }
11093 break;
11094 }
11095 case IPPROTO_UDP: {
11096 struct udphdr uh;
11097 if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11098 m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11099 SIN6(&local_addr)->sin6_port = uh.uh_sport;
11100 SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11101 }
11102 break;
11103 }
11104 default: {
11105 SIN6(&local_addr)->sin6_port = 0;
11106 SIN6(&remote_addr)->sin6_port = 0;
11107 break;
11108 }
11109 }
11110 }
11111
11112 // Match packet to policy
11113 lck_rw_lock_shared(&necp_kernel_policy_lock);
11114 u_int32_t route_rule_id = 0;
11115
11116 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11117 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11118
11119 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);
11120 if (matched_policy) {
11121 matched_policy_id = matched_policy->id;
11122 if (result) {
11123 *result = matched_policy->result;
11124 }
11125
11126 if (result_parameter) {
11127 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11128 }
11129
11130 if (route_rule_id != 0 &&
11131 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11132 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11133 }
11134
11135 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11136 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);
11137 }
11138 } else {
11139 bool drop_all = false;
11140 /*
11141 * Apply drop-all only to packets which have never matched a primary policy (check
11142 * if the packet saved policy id is none or falls within the socket policy id range).
11143 */
11144 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11145 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11146 drop_all = true;
11147 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11148 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11149 }
11150 }
11151 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11152 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11153 if (result) {
11154 *result = NECP_KERNEL_POLICY_RESULT_DROP;
11155 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11156 }
11157 } else if (route_rule_id != 0 &&
11158 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11159 // If we matched a route rule, mark it
11160 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11161 }
11162 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11163 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);
11164 }
11165 }
11166
11167 lck_rw_done(&necp_kernel_policy_lock);
11168
11169 return matched_policy_id;
11170 }
11171
11172 // Utilities
11173 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11174 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11175 {
11176 int cmp = 0;
11177
11178 if (addr == NULL || range_start == NULL || range_end == NULL) {
11179 return FALSE;
11180 }
11181
11182 /* Must be greater than or equal to start */
11183 cmp = necp_addr_compare(addr, range_start, 1);
11184 if (cmp != 0 && cmp != 1) {
11185 return FALSE;
11186 }
11187
11188 /* Must be less than or equal to end */
11189 cmp = necp_addr_compare(addr, range_end, 1);
11190 if (cmp != 0 && cmp != -1) {
11191 return FALSE;
11192 }
11193
11194 return TRUE;
11195 }
11196
11197 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)11198 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11199 {
11200 int cmp = 0;
11201
11202 if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11203 return FALSE;
11204 }
11205
11206 /* Must be greater than or equal to start */
11207 cmp = necp_addr_compare(inner_range_start, range_start, 1);
11208 if (cmp != 0 && cmp != 1) {
11209 return FALSE;
11210 }
11211
11212 /* Must be less than or equal to end */
11213 cmp = necp_addr_compare(inner_range_end, range_end, 1);
11214 if (cmp != 0 && cmp != -1) {
11215 return FALSE;
11216 }
11217
11218 return TRUE;
11219 }
11220
11221 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11222 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11223 {
11224 if (addr == NULL || subnet_addr == NULL) {
11225 return FALSE;
11226 }
11227
11228 if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11229 return FALSE;
11230 }
11231
11232 switch (addr->sa_family) {
11233 case AF_INET: {
11234 if (satosin(subnet_addr)->sin_port != 0 &&
11235 satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11236 return FALSE;
11237 }
11238 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11239 }
11240 case AF_INET6: {
11241 if (satosin6(subnet_addr)->sin6_port != 0 &&
11242 satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11243 return FALSE;
11244 }
11245 if (satosin6(addr)->sin6_scope_id &&
11246 satosin6(subnet_addr)->sin6_scope_id &&
11247 satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11248 return FALSE;
11249 }
11250 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11251 }
11252 default: {
11253 return FALSE;
11254 }
11255 }
11256
11257 return FALSE;
11258 }
11259
11260 /*
11261 * Return values:
11262 * -1: sa1 < sa2
11263 * 0: sa1 == sa2
11264 * 1: sa1 > sa2
11265 * 2: Not comparable or error
11266 */
11267 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11268 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11269 {
11270 int result = 0;
11271 int port_result = 0;
11272
11273 if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11274 return 2;
11275 }
11276
11277 if (sa1->sa_len == 0) {
11278 return 0;
11279 }
11280
11281 switch (sa1->sa_family) {
11282 case AF_INET: {
11283 if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11284 return 2;
11285 }
11286
11287 result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11288
11289 if (check_port) {
11290 if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11291 port_result = -1;
11292 } else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11293 port_result = 1;
11294 }
11295
11296 if (result == 0) {
11297 result = port_result;
11298 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11299 return 2;
11300 }
11301 }
11302
11303 break;
11304 }
11305 case AF_INET6: {
11306 if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11307 return 2;
11308 }
11309
11310 if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11311 return 2;
11312 }
11313
11314 result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11315
11316 if (check_port) {
11317 if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11318 port_result = -1;
11319 } else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11320 port_result = 1;
11321 }
11322
11323 if (result == 0) {
11324 result = port_result;
11325 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11326 return 2;
11327 }
11328 }
11329
11330 break;
11331 }
11332 default: {
11333 result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11334 break;
11335 }
11336 }
11337
11338 if (result < 0) {
11339 result = (-1);
11340 } else if (result > 0) {
11341 result = (1);
11342 }
11343
11344 return result;
11345 }
11346
11347 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11348 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11349 {
11350 u_int8_t mask;
11351
11352 /* Handle null pointers */
11353 if (p1 == NULL || p2 == NULL) {
11354 return p1 == p2;
11355 }
11356
11357 while (bits >= 8) {
11358 if (*p1++ != *p2++) {
11359 return FALSE;
11360 }
11361 bits -= 8;
11362 }
11363
11364 if (bits > 0) {
11365 mask = ~((1 << (8 - bits)) - 1);
11366 if ((*p1 & mask) != (*p2 & mask)) {
11367 return FALSE;
11368 }
11369 }
11370 return TRUE;
11371 }
11372
11373 static bool
necp_addr_is_empty(struct sockaddr * addr)11374 necp_addr_is_empty(struct sockaddr *addr)
11375 {
11376 if (addr == NULL) {
11377 return TRUE;
11378 }
11379
11380 if (addr->sa_len == 0) {
11381 return TRUE;
11382 }
11383
11384 switch (addr->sa_family) {
11385 case AF_INET: {
11386 static struct sockaddr_in ipv4_empty_address = {
11387 .sin_len = sizeof(struct sockaddr_in),
11388 .sin_family = AF_INET,
11389 .sin_port = 0,
11390 .sin_addr = { .s_addr = 0 }, // 0.0.0.0
11391 .sin_zero = {0},
11392 };
11393 if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11394 return TRUE;
11395 } else {
11396 return FALSE;
11397 }
11398 }
11399 case AF_INET6: {
11400 static struct sockaddr_in6 ipv6_empty_address = {
11401 .sin6_len = sizeof(struct sockaddr_in6),
11402 .sin6_family = AF_INET6,
11403 .sin6_port = 0,
11404 .sin6_flowinfo = 0,
11405 .sin6_addr = IN6ADDR_ANY_INIT, // ::
11406 .sin6_scope_id = 0,
11407 };
11408 if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11409 return TRUE;
11410 } else {
11411 return FALSE;
11412 }
11413 }
11414 default:
11415 return FALSE;
11416 }
11417
11418 return FALSE;
11419 }
11420
11421 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)11422 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)
11423 {
11424 bool qos_marking = FALSE;
11425 int exception_index = 0;
11426 struct necp_route_rule *route_rule = NULL;
11427
11428 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11429 if (route_rule == NULL) {
11430 qos_marking = FALSE;
11431 goto done;
11432 }
11433
11434 if (route_rule->match_netagent_id != 0) {
11435 if (netagent_array == NULL || netagent_array_count == 0) {
11436 // No agents, ignore rule
11437 goto done;
11438 }
11439 bool found_match = FALSE;
11440 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11441 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11442 found_match = TRUE;
11443 break;
11444 }
11445 }
11446 if (!found_match) {
11447 // Agents don't match, ignore rule
11448 goto done;
11449 }
11450 }
11451
11452 qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11453
11454 if (ifp == NULL) {
11455 goto done;
11456 }
11457
11458 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11459 if (route_rule->exception_if_indices[exception_index] == 0) {
11460 break;
11461 }
11462 if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
11463 continue;
11464 }
11465 if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
11466 qos_marking = TRUE;
11467 if (necp_debug > 2) {
11468 NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
11469 route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
11470 }
11471 goto done;
11472 }
11473 }
11474
11475 if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
11476 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
11477 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
11478 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
11479 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
11480 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
11481 (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
11482 qos_marking = TRUE;
11483 if (necp_debug > 2) {
11484 NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d for Rule %d Allowed %d",
11485 route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
11486 route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action, route_rule_id, qos_marking);
11487 }
11488 goto done;
11489 }
11490 done:
11491 if (necp_debug > 1) {
11492 NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
11493 route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
11494 }
11495 return qos_marking;
11496 }
11497
11498 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)11499 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)
11500 {
11501 bool new_qos_marking = old_qos_marking;
11502 struct ifnet *ifp = interface;
11503
11504 if (net_qos_policy_restricted == 0) {
11505 return new_qos_marking;
11506 }
11507
11508 /*
11509 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
11510 */
11511 if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
11512 return new_qos_marking;
11513 }
11514
11515 lck_rw_lock_shared(&necp_kernel_policy_lock);
11516
11517 if (ifp == NULL && route != NULL) {
11518 ifp = route->rt_ifp;
11519 }
11520 /*
11521 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
11522 */
11523 if (ifp == NULL || route_rule_id == 0) {
11524 new_qos_marking = FALSE;
11525 goto done;
11526 }
11527
11528 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11529 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11530 if (aggregate_route_rule != NULL) {
11531 int index = 0;
11532 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11533 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11534 if (sub_route_rule_id == 0) {
11535 break;
11536 }
11537 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
11538 if (new_qos_marking == TRUE) {
11539 break;
11540 }
11541 }
11542 }
11543 } else {
11544 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
11545 }
11546 /*
11547 * Now that we have an interface we remember the gencount
11548 */
11549 *qos_marking_gencount = necp_kernel_socket_policies_gencount;
11550
11551 done:
11552 lck_rw_done(&necp_kernel_policy_lock);
11553 return new_qos_marking;
11554 }
11555
11556 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)11557 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11558 {
11559 bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11560
11561 if (net_qos_policy_restricted == 0) {
11562 return;
11563 }
11564 if (inp->inp_socket == NULL) {
11565 return;
11566 }
11567 if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11568 return;
11569 }
11570
11571 qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
11572
11573 if (qos_marking == TRUE) {
11574 inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
11575 } else {
11576 inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
11577 }
11578 }
11579
11580 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)11581 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
11582 {
11583 if (ifp != NULL &&
11584 (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11585 ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11586 return true;
11587 }
11588 if (delegated_ifp != NULL &&
11589 (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11590 delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11591 return true;
11592 }
11593 return false;
11594 }
11595
11596 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)11597 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,
11598 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11599 {
11600 bool default_is_allowed = TRUE;
11601 u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
11602 int exception_index = 0;
11603 struct ifnet *delegated_ifp = NULL;
11604 struct necp_route_rule *route_rule = NULL;
11605
11606 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11607 if (route_rule == NULL) {
11608 return TRUE;
11609 }
11610
11611 if (route_rule->match_netagent_id != 0) {
11612 if (netagent_array == NULL || netagent_array_count == 0) {
11613 // No agents, ignore rule
11614 return TRUE;
11615 }
11616 bool found_match = FALSE;
11617 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11618 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11619 found_match = TRUE;
11620 break;
11621 }
11622 }
11623 if (!found_match) {
11624 // Agents don't match, ignore rule
11625 return TRUE;
11626 }
11627 }
11628
11629 default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
11630 if (ifp == NULL && route != NULL) {
11631 ifp = route->rt_ifp;
11632 }
11633 if (ifp == NULL) {
11634 if (necp_debug > 1 && !default_is_allowed) {
11635 NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
11636 }
11637 return default_is_allowed;
11638 }
11639
11640 delegated_ifp = ifp->if_delegated.ifp;
11641 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11642 if (route_rule->exception_if_indices[exception_index] == 0) {
11643 break;
11644 }
11645 if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
11646 (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
11647 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11648 const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
11649 if (necp_debug > 1 && lqm_abort) {
11650 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
11651 route_rule->exception_if_indices[exception_index], route_rule_id);
11652 }
11653 return false;
11654 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
11655 if (necp_debug > 1) {
11656 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));
11657 }
11658 if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
11659 *interface_type_denied = route_rule->effective_type;
11660 }
11661 return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
11662 }
11663 }
11664 }
11665
11666 if (IFNET_IS_CELLULAR(ifp)) {
11667 if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11668 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11669 if (interface_type_denied != NULL) {
11670 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
11671 if (route_rule->effective_type != 0) {
11672 *interface_type_denied = route_rule->effective_type;
11673 }
11674 }
11675 // Mark aggregate action as deny
11676 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11677 }
11678 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
11679 if (interface_type_denied != NULL) {
11680 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
11681 if (route_rule->effective_type != 0) {
11682 *interface_type_denied = route_rule->effective_type;
11683 }
11684 }
11685 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11686 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11687 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
11688 // Deny wins if there is a conflict
11689 type_aggregate_action = route_rule->cellular_action;
11690 }
11691 }
11692 }
11693
11694 if (IFNET_IS_WIFI(ifp)) {
11695 if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11696 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11697 if (interface_type_denied != NULL) {
11698 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
11699 if (route_rule->effective_type != 0) {
11700 *interface_type_denied = route_rule->effective_type;
11701 }
11702 }
11703 // Mark aggregate action as deny
11704 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11705 }
11706 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
11707 if (interface_type_denied != NULL) {
11708 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
11709 if (route_rule->effective_type != 0) {
11710 *interface_type_denied = route_rule->effective_type;
11711 }
11712 }
11713 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11714 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11715 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
11716 // Deny wins if there is a conflict
11717 type_aggregate_action = route_rule->wifi_action;
11718 }
11719 }
11720 }
11721
11722 if (IFNET_IS_COMPANION_LINK(ifp) ||
11723 (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
11724 if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11725 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11726 if (interface_type_denied != NULL) {
11727 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
11728 if (route_rule->effective_type != 0) {
11729 *interface_type_denied = route_rule->effective_type;
11730 }
11731 }
11732 // Mark aggregate action as deny
11733 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11734 }
11735 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
11736 if (interface_type_denied != NULL) {
11737 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
11738 if (route_rule->effective_type != 0) {
11739 *interface_type_denied = route_rule->effective_type;
11740 }
11741 }
11742 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11743 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11744 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
11745 // Deny wins if there is a conflict
11746 type_aggregate_action = route_rule->companion_action;
11747 }
11748 }
11749 }
11750
11751 if (IFNET_IS_WIRED(ifp)) {
11752 if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11753 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11754 if (interface_type_denied != NULL) {
11755 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
11756 if (route_rule->effective_type != 0) {
11757 *interface_type_denied = route_rule->effective_type;
11758 }
11759 }
11760 // Mark aggregate action as deny
11761 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11762 }
11763 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
11764 if (interface_type_denied != NULL) {
11765 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
11766 if (route_rule->effective_type != 0) {
11767 *interface_type_denied = route_rule->effective_type;
11768 }
11769 }
11770 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11771 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11772 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
11773 // Deny wins if there is a conflict
11774 type_aggregate_action = route_rule->wired_action;
11775 }
11776 }
11777 }
11778
11779 if (IFNET_IS_EXPENSIVE(ifp)) {
11780 if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11781 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11782 // Mark aggregate action as deny
11783 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11784 }
11785 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
11786 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11787 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11788 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
11789 // Deny wins if there is a conflict
11790 type_aggregate_action = route_rule->expensive_action;
11791 }
11792 }
11793 }
11794
11795 if (IFNET_IS_CONSTRAINED(ifp)) {
11796 if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11797 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11798 // Mark aggregate action as deny
11799 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11800 }
11801 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
11802 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11803 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11804 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
11805 // Deny wins if there is a conflict
11806 type_aggregate_action = route_rule->constrained_action;
11807 }
11808 }
11809 }
11810
11811 if (IFNET_IS_VPN(ifp)) {
11812 if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11813 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11814 // Mark aggregate action as deny
11815 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11816 }
11817 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
11818 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11819 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11820 IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
11821 // Deny wins if there is a conflict
11822 type_aggregate_action = route_rule->vpn_action;
11823 }
11824 }
11825 }
11826
11827 if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
11828 if (necp_debug > 1) {
11829 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));
11830 }
11831 return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
11832 }
11833
11834 if (necp_debug > 1 && !default_is_allowed) {
11835 NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
11836 }
11837 return default_is_allowed;
11838 }
11839
11840 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)11841 necp_proc_is_allowed_on_management_interface(proc_t proc)
11842 {
11843 bool allowed = false;
11844 const task_t __single task = proc_task(proc);
11845
11846 if (task != NULL) {
11847 if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
11848 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
11849 #if DEBUG || DEVELOPMENT
11850 || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
11851 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
11852 #endif /* DEBUG || DEVELOPMENT */
11853 ) {
11854 allowed = true;
11855 }
11856 }
11857 return allowed;
11858 }
11859
11860 __attribute__((noinline))
11861 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)11862 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
11863 {
11864 char buf[128];
11865
11866 if (inp != NULL) {
11867 inp_snprintf_tuple(inp, buf, sizeof(buf));
11868 } else {
11869 *buf = 0;
11870 }
11871 os_log(OS_LOG_DEFAULT,
11872 "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
11873 proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
11874 proc != NULL ? proc_getpid(proc) : proc_selfpid(),
11875 inp != NULL ? buf : "",
11876 ifp->if_xname);
11877 }
11878
11879 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)11880 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
11881 {
11882 if (if_management_interface_check_needed == false) {
11883 return true;
11884 }
11885 if (necp_drop_management_order == 0) {
11886 return true;
11887 }
11888 if (ifp == NULL && route != NULL) {
11889 ifp = route->rt_ifp;
11890 }
11891 if (ifp == NULL) {
11892 return true;
11893 }
11894
11895 if (IFNET_IS_MANAGEMENT(ifp)) {
11896 bool allowed = true;
11897
11898 if (inp != NULL) {
11899 /*
11900 * The entitlement check is already performed for socket flows
11901 */
11902 allowed = INP_MANAGEMENT_ALLOWED(inp);
11903 } else if (proc != NULL) {
11904 allowed = necp_proc_is_allowed_on_management_interface(proc);
11905 }
11906 if (__improbable(if_management_verbose > 1 && allowed == false)) {
11907 necp_log_interface_not_allowed(ifp, proc, inp);
11908 }
11909 return allowed;
11910 }
11911 return true;
11912 }
11913
11914 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)11915 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,
11916 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11917 {
11918 if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
11919 if (necp_debug > 1) {
11920 NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
11921 }
11922 return TRUE;
11923 }
11924
11925 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11926 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11927 if (aggregate_route_rule != NULL) {
11928 int index = 0;
11929 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11930 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11931 if (sub_route_rule_id == 0) {
11932 break;
11933 }
11934 if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
11935 return FALSE;
11936 }
11937 }
11938 }
11939 } else {
11940 return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
11941 }
11942
11943 return TRUE;
11944 }
11945
11946 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)11947 necp_route_rule_matches_agents(u_int32_t route_rule_id)
11948 {
11949 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11950 if (route_rule == NULL) {
11951 return false;
11952 }
11953
11954 return route_rule->match_netagent_id != 0;
11955 }
11956
11957 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)11958 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)
11959 {
11960 if (remove == NULL) {
11961 return 0;
11962 }
11963
11964 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11965 if (route_rule == NULL) {
11966 return 0;
11967 }
11968
11969 // No netagent, skip
11970 if (route_rule->netagent_id == 0) {
11971 return 0;
11972 }
11973
11974 if (route_rule->match_netagent_id != 0) {
11975 if (netagent_array == NULL || netagent_array_count == 0) {
11976 // No agents, ignore rule
11977 return 0;
11978 }
11979 bool found_match = FALSE;
11980 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11981 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11982 found_match = TRUE;
11983 break;
11984 }
11985 }
11986 if (!found_match) {
11987 // Agents don't match, ignore rule
11988 return 0;
11989 }
11990 }
11991
11992 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
11993 if (ifp == NULL) {
11994 // No interface, apply the default action
11995 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11996 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11997 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11998 return route_rule->netagent_id;
11999 }
12000 return 0;
12001 }
12002
12003 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12004 if (route_rule->exception_if_indices[exception_index] == 0) {
12005 break;
12006 }
12007 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12008 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12009 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12010 route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12011 *remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12012 return route_rule->netagent_id;
12013 }
12014 return 0;
12015 }
12016 }
12017
12018 if (ifp->if_type == IFT_CELLULAR &&
12019 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12020 if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12021 route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12022 *remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12023 return route_rule->netagent_id;
12024 }
12025 return 0;
12026 }
12027
12028 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12029 route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12030 if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12031 route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12032 *remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12033 return route_rule->netagent_id;
12034 }
12035 return 0;
12036 }
12037
12038 if (IFNET_IS_COMPANION_LINK(ifp) &&
12039 route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12040 if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12041 route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12042 *remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12043 return route_rule->netagent_id;
12044 }
12045 return 0;
12046 }
12047
12048 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12049 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12050 if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12051 route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12052 *remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12053 return route_rule->netagent_id;
12054 }
12055 return 0;
12056 }
12057
12058 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12059 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12060 if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12061 route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12062 *remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12063 return route_rule->netagent_id;
12064 }
12065 return 0;
12066 }
12067
12068 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12069 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12070 if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12071 route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12072 *remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12073 return route_rule->netagent_id;
12074 }
12075 return 0;
12076 }
12077
12078 if (ifp->if_xflags & IFXF_IS_VPN &&
12079 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12080 if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12081 route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12082 *remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12083 return route_rule->netagent_id;
12084 }
12085 return 0;
12086 }
12087
12088 // No more specific case matched, apply the default action
12089 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12090 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12091 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12092 return route_rule->netagent_id;
12093 }
12094
12095 return 0;
12096 }
12097
12098 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)12099 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)
12100 {
12101 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12102 if (route_rule == NULL) {
12103 return 0;
12104 }
12105
12106 // No control unit, skip
12107 if (route_rule->control_unit == 0) {
12108 return 0;
12109 }
12110
12111 if (route_rule->match_netagent_id != 0) {
12112 if (netagent_array == NULL || netagent_array_count == 0) {
12113 // No agents, ignore rule
12114 return 0;
12115 }
12116 bool found_match = FALSE;
12117 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12118 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12119 found_match = TRUE;
12120 break;
12121 }
12122 }
12123 if (!found_match) {
12124 // Agents don't match, ignore rule
12125 return 0;
12126 }
12127 }
12128
12129 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12130 if (ifp == NULL) {
12131 // No interface, apply the default action
12132 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12133 return route_rule->control_unit;
12134 }
12135 return 0;
12136 }
12137
12138 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12139 if (route_rule->exception_if_indices[exception_index] == 0) {
12140 break;
12141 }
12142 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12143 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12144 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12145 return route_rule->control_unit;
12146 }
12147 return 0;
12148 }
12149 }
12150
12151 if (ifp->if_type == IFT_CELLULAR &&
12152 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12153 if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12154 return route_rule->control_unit;
12155 }
12156 return 0;
12157 }
12158
12159 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12160 route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12161 if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12162 return route_rule->control_unit;
12163 }
12164 return 0;
12165 }
12166
12167 if (IFNET_IS_COMPANION_LINK(ifp) &&
12168 route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12169 if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12170 return route_rule->control_unit;
12171 }
12172 return 0;
12173 }
12174
12175 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12176 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12177 if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12178 return route_rule->control_unit;
12179 }
12180 return 0;
12181 }
12182
12183 if (ifp->if_eflags & IFEF_EXPENSIVE &&
12184 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12185 if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12186 return route_rule->control_unit;
12187 }
12188 return 0;
12189 }
12190
12191 if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12192 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12193 if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12194 return route_rule->control_unit;
12195 }
12196 return 0;
12197 }
12198
12199 if (ifp->if_xflags & IFXF_IS_VPN &&
12200 route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12201 if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12202 return route_rule->control_unit;
12203 }
12204 return 0;
12205 }
12206
12207 // No more specific case matched, apply the default action
12208 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12209 return route_rule->control_unit;
12210 }
12211 return 0;
12212 }
12213
12214 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)12215 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,
12216 u_int32_t *flow_divert_aggregate_unit)
12217 {
12218 if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12219 return 0;
12220 }
12221
12222 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12223 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12224 if (aggregate_route_rule != NULL) {
12225 int index = 0;
12226 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12227 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12228 if (sub_route_rule_id == 0) {
12229 break;
12230 }
12231 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12232 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12233 // For transparent proxies, accumulate the control unit and continue to the next route rule
12234 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12235 continue;
12236 }
12237
12238 if (control_unit != 0) {
12239 return control_unit;
12240 }
12241 }
12242 }
12243 } else {
12244 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12245 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12246 // For transparent proxies, accumulate the control unit and let the caller continue
12247 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12248 return 0;
12249 }
12250 return control_unit;
12251 }
12252
12253 return 0;
12254 }
12255
12256 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12257 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12258 {
12259 bool is_allowed = true;
12260 u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12261 if (route_rule_id != 0 &&
12262 interface != NULL) {
12263 lck_rw_lock_shared(&necp_kernel_policy_lock);
12264 is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
12265 lck_rw_done(&necp_kernel_policy_lock);
12266 }
12267 return is_allowed;
12268 }
12269
12270 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12271 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12272 {
12273 size_t netagent_cursor;
12274 for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12275 struct necp_uuid_id_mapping *mapping = NULL;
12276 u_int32_t netagent_id = netagent_ids[netagent_cursor];
12277 if (netagent_id == 0) {
12278 continue;
12279 }
12280 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
12281 if (mapping != NULL) {
12282 u_int32_t agent_flags = 0;
12283 agent_flags = netagent_get_flags(mapping->uuid);
12284 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12285 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12286 continue;
12287 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12288 return FALSE;
12289 }
12290 }
12291 }
12292 }
12293 return TRUE;
12294 }
12295
12296 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12297 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12298 {
12299 bool allowed_to_receive = TRUE;
12300
12301 if (pf_tag == PF_TAG_ID_STACK_DROP &&
12302 (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12303 allowed_to_receive = FALSE;
12304 }
12305
12306 return allowed_to_receive;
12307 }
12308
12309 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)12310 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)
12311 {
12312 u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12313 bool allowed_to_receive = TRUE;
12314 struct necp_socket_info info = {};
12315 u_int32_t flowhash = 0;
12316 necp_kernel_policy_result service_action = 0;
12317 necp_kernel_policy_service service = { 0, 0 };
12318 u_int32_t route_rule_id = 0;
12319 struct rtentry *route = NULL;
12320 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12321 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12322 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12323 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12324 proc_t __single socket_proc = NULL;
12325 necp_kernel_policy_filter filter_control_unit = 0;
12326 u_int32_t pass_flags = 0;
12327 u_int32_t flow_divert_aggregate_unit = 0;
12328 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12329 int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12330
12331 memset(&netagent_ids, 0, sizeof(netagent_ids));
12332
12333 if (return_policy_id) {
12334 *return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12335 }
12336 if (return_skip_policy_id) {
12337 *return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12338 }
12339 if (return_route_rule_id) {
12340 *return_route_rule_id = 0;
12341 }
12342 if (return_pass_flags) {
12343 *return_pass_flags = 0;
12344 }
12345
12346 if (inp == NULL) {
12347 goto done;
12348 }
12349
12350 route = inp->inp_route.ro_rt;
12351
12352 struct socket *so = inp->inp_socket;
12353
12354 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12355
12356 // Don't lock. Possible race condition, but we don't want the performance hit.
12357 if (necp_drop_management_order == 0 &&
12358 (necp_kernel_socket_policies_count == 0 ||
12359 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12360 if (necp_drop_all_order > 0 || drop_order > 0) {
12361 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12362 if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12363 allowed_to_receive = TRUE;
12364 } else {
12365 allowed_to_receive = FALSE;
12366 }
12367 }
12368 goto done;
12369 }
12370
12371 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
12372 if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12373 bool policies_have_changed = FALSE;
12374 bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12375 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12376 policies_have_changed = TRUE;
12377 } else {
12378 if (inp->inp_policyresult.results.route_rule_id != 0) {
12379 lck_rw_lock_shared(&necp_kernel_policy_lock);
12380 if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
12381 route_allowed = FALSE;
12382 }
12383 lck_rw_done(&necp_kernel_policy_lock);
12384 }
12385 }
12386
12387 if (!policies_have_changed) {
12388 if (debug) {
12389 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, input_interface != NULL ? true : false, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
12390 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12391 }
12392
12393 if (!route_allowed ||
12394 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12395 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12396 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12397 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12398 allowed_to_receive = FALSE;
12399 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);
12400 } else {
12401 if (return_policy_id) {
12402 *return_policy_id = inp->inp_policyresult.policy_id;
12403 }
12404 if (return_skip_policy_id) {
12405 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12406 }
12407 if (return_route_rule_id) {
12408 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12409 }
12410 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12411 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12412 }
12413 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);
12414 }
12415 goto done;
12416 }
12417 }
12418
12419 // Check for loopback exception
12420 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12421 if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12422 allowed_to_receive = FALSE;
12423 goto done;
12424 }
12425 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
12426 allowed_to_receive = TRUE;
12427 goto done;
12428 }
12429
12430 // Actually calculate policy result
12431 lck_rw_lock_shared(&necp_kernel_policy_lock);
12432 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, input_interface != NULL ? true : false, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
12433
12434 debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12435 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
12436
12437 flowhash = necp_socket_calc_flowhash_locked(&info);
12438 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12439 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
12440 inp->inp_policyresult.flowhash == flowhash) {
12441 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12442 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12443 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12444 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
12445 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12446 (inp->inp_policyresult.results.route_rule_id != 0 &&
12447 !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
12448 allowed_to_receive = FALSE;
12449 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);
12450 } else {
12451 if (return_policy_id) {
12452 *return_policy_id = inp->inp_policyresult.policy_id;
12453 }
12454 if (return_route_rule_id) {
12455 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12456 }
12457 if (return_skip_policy_id) {
12458 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12459 }
12460 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12461 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12462 }
12463 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12464 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",
12465 inp->inp_socket, info.bound_interface_index, info.protocol,
12466 inp->inp_policyresult.policy_id,
12467 inp->inp_policyresult.skip_policy_id,
12468 inp->inp_policyresult.results.result,
12469 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
12470 }
12471 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
12472 return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12473 }
12474 lck_rw_done(&necp_kernel_policy_lock);
12475 goto done;
12476 }
12477
12478 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
12479 size_t route_rule_id_array_count = 0;
12480 proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
12481 struct necp_kernel_socket_policy *matched_policy =
12482 necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
12483 &info,
12484 &filter_control_unit,
12485 route_rule_id_array,
12486 &route_rule_id_array_count,
12487 MAX_AGGREGATE_ROUTE_RULES,
12488 &service_action,
12489 &service,
12490 netagent_ids,
12491 NECP_MAX_NETAGENTS,
12492 NULL,
12493 0,
12494 NULL,
12495 0,
12496 effective_proc,
12497 pf_tag,
12498 return_skip_policy_id,
12499 inp->inp_route.ro_rt,
12500 &drop_dest_policy_result,
12501 &drop_all_bypass,
12502 &flow_divert_aggregate_unit,
12503 so,
12504 debug);
12505
12506 // Check for loopback exception again after the policy match
12507 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
12508 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
12509 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
12510 // If policies haven't changed since last evaluation, do not update filter result in order to
12511 // preserve the very first filter result for the socket. Otherwise, update the filter result to
12512 // allow content filter to detect and drop pre-existing flows.
12513 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12514 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12515 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12516 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12517 }
12518 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12519 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12520 }
12521 allowed_to_receive = TRUE;
12522 lck_rw_done(&necp_kernel_policy_lock);
12523
12524 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);
12525 goto done;
12526 }
12527
12528 if (info.protocol != IPPROTO_UDP) {
12529 goto skip_agent_check;
12530 }
12531
12532 // Verify netagents
12533 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
12534 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12535 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);
12536 }
12537
12538 // Mark socket as a drop if required agent is not active
12539 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12540 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12541 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12542 inp->inp_policyresult.flowhash = flowhash;
12543 inp->inp_policyresult.results.filter_control_unit = 0;
12544 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
12545 inp->inp_policyresult.results.route_rule_id = 0;
12546 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
12547
12548 // Unlock
12549 allowed_to_receive = FALSE;
12550 lck_rw_done(&necp_kernel_policy_lock);
12551
12552 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);
12553
12554 goto done;
12555 }
12556
12557 skip_agent_check:
12558
12559 if (route_rule_id_array_count == 1) {
12560 route_rule_id = route_rule_id_array[0];
12561 } else if (route_rule_id_array_count > 1) {
12562 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
12563 }
12564
12565 bool send_local_network_denied_event = false;
12566 if (matched_policy != NULL) {
12567 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
12568 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
12569 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
12570 // Trigger the event that we dropped due to a local network policy
12571 send_local_network_denied_event = true;
12572 }
12573
12574 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
12575 matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12576 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12577 matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
12578 !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12579 (route_rule_id != 0 &&
12580 !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
12581 !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
12582 allowed_to_receive = FALSE;
12583 } else {
12584 if (return_policy_id) {
12585 *return_policy_id = matched_policy->id;
12586 }
12587 if (return_route_rule_id) {
12588 *return_route_rule_id = route_rule_id;
12589 }
12590 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
12591 pass_flags = matched_policy->result_parameter.pass_flags;
12592 }
12593 // If policies haven't changed since last evaluation, do not update filter result in order to
12594 // preserve the very first filter result for the socket. Otherwise, update the filter result to
12595 // allow content filter to detect and drop pre-existing flows.
12596 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12597 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12598 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12599 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12600 }
12601 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12602 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12603 }
12604 }
12605
12606 if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
12607 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>",
12608 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);
12609 }
12610 } else {
12611 bool drop_all = false;
12612 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
12613 drop_all = true;
12614 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
12615 drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
12616 }
12617 }
12618 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
12619 allowed_to_receive = FALSE;
12620 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
12621 } else {
12622 if (return_policy_id) {
12623 *return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12624 }
12625 if (return_route_rule_id) {
12626 *return_route_rule_id = route_rule_id;
12627 }
12628
12629 // If policies haven't changed since last evaluation, do not update filter result in order to
12630 // preserve the very first filter result for the socket. Otherwise, update the filter result to
12631 // allow content filter to detect and drop pre-existing flows.
12632 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12633 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12634 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12635 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12636 }
12637 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12638 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12639 }
12640 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);
12641 }
12642 }
12643
12644 if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
12645 allowed_to_receive = FALSE;
12646 NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
12647 }
12648
12649 lck_rw_done(&necp_kernel_policy_lock);
12650
12651 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
12652 inp->inp_policyresult.network_denied_notifies++;
12653 #if defined(XNU_TARGET_OS_OSX)
12654 bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
12655 necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
12656 should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
12657 NETPOLICY_NETWORKTYPE_LOCAL);
12658 #else
12659 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
12660 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
12661 NETPOLICY_NETWORKTYPE_LOCAL);
12662 #endif
12663 }
12664
12665 done:
12666 if (return_pass_flags != NULL) {
12667 *return_pass_flags = pass_flags;
12668 }
12669
12670 if (pf_tag != 0 && allowed_to_receive) {
12671 allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
12672 }
12673
12674 if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
12675 soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
12676 }
12677
12678 if (socket_proc) {
12679 proc_rele(socket_proc);
12680 }
12681
12682 return allowed_to_receive;
12683 }
12684
12685 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)12686 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)
12687 {
12688 struct sockaddr_in local = {};
12689 struct sockaddr_in remote = {};
12690 local.sin_family = remote.sin_family = AF_INET;
12691 local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
12692 local.sin_port = local_port;
12693 remote.sin_port = remote_port;
12694 memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
12695 memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
12696
12697 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
12698 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
12699 }
12700
12701 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)12702 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)
12703 {
12704 struct sockaddr_in6 local = {};
12705 struct sockaddr_in6 remote = {};
12706 local.sin6_family = remote.sin6_family = AF_INET6;
12707 local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
12708 local.sin6_port = local_port;
12709 remote.sin6_port = remote_port;
12710 memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
12711 memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
12712
12713 return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
12714 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
12715 }
12716
12717 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)12718 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,
12719 u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
12720 {
12721 return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
12722 return_policy_id, return_route_rule_id,
12723 return_skip_policy_id, return_pass_flags);
12724 }
12725
12726 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)12727 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
12728 necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
12729 {
12730 if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
12731 return EINVAL;
12732 }
12733
12734 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
12735 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
12736 policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
12737 }
12738
12739 // Mark ID for Pass and IP Tunnel
12740 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12741 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12742 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
12743 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
12744 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
12745 } else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
12746 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
12747 // This case is same as a PASS
12748 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
12749 } else {
12750 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12751 }
12752 packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
12753 if (route_rule_id != 0) {
12754 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
12755 } else {
12756 packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12757 }
12758 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);
12759
12760 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12761 skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
12762 // Only mark the skip policy if it is a valid policy ID
12763 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
12764 } else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12765 inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
12766 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12767 } else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
12768 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
12769 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
12770 // See necp_get_skip_policy_id_from_packet() and
12771 // necp_packet_should_skip_filters().
12772 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12773 } else {
12774 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12775 }
12776
12777 if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
12778 ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
12779 m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
12780 }
12781
12782 if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
12783 NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
12784 packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
12785 }
12786
12787 return 0;
12788 }
12789
12790 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)12791 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
12792 {
12793 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12794 return EINVAL;
12795 }
12796
12797 // Mark ID for Pass and IP Tunnel
12798 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12799 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12800 } else {
12801 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12802 }
12803
12804 return 0;
12805 }
12806
12807 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)12808 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
12809 {
12810 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12811 return EINVAL;
12812 }
12813
12814 // Mark ID for Pass and IP Tunnel
12815 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12816 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12817 } else {
12818 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12819 }
12820
12821 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12822 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
12823 } else {
12824 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12825 }
12826 return 0;
12827 }
12828
12829 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)12830 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
12831 {
12832 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12833 return EINVAL;
12834 }
12835
12836 // Mark ID for Pass and IP Tunnel
12837 if (interface != NULL) {
12838 packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
12839 }
12840
12841 return 0;
12842 }
12843
12844 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)12845 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
12846 {
12847 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12848 return EINVAL;
12849 }
12850
12851 if (is_keepalive) {
12852 packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
12853 } else {
12854 packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
12855 }
12856
12857 return 0;
12858 }
12859
12860 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)12861 necp_get_policy_id_from_packet(struct mbuf *packet)
12862 {
12863 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12864 return NECP_KERNEL_POLICY_ID_NONE;
12865 }
12866
12867 return packet->m_pkthdr.necp_mtag.necp_policy_id;
12868 }
12869
12870 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)12871 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
12872 {
12873 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12874 return NECP_KERNEL_POLICY_ID_NONE;
12875 }
12876
12877 // Check for overloaded value. See necp_mark_packet_from_socket().
12878 if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
12879 return NECP_KERNEL_POLICY_ID_NONE;
12880 }
12881
12882 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
12883 }
12884
12885 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)12886 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
12887 {
12888 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12889 return 0;
12890 }
12891
12892 return m_pftag(packet)->pftag_tag;
12893 }
12894
12895 bool
necp_packet_should_skip_filters(struct mbuf * packet)12896 necp_packet_should_skip_filters(struct mbuf *packet)
12897 {
12898 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12899 return false;
12900 }
12901
12902 // Check for overloaded value. See necp_mark_packet_from_socket().
12903 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
12904 }
12905
12906 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)12907 necp_get_last_interface_index_from_packet(struct mbuf *packet)
12908 {
12909 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12910 return 0;
12911 }
12912
12913 return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
12914 }
12915
12916 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)12917 necp_get_route_rule_id_from_packet(struct mbuf *packet)
12918 {
12919 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12920 return 0;
12921 }
12922
12923 return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
12924 }
12925
12926 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)12927 necp_get_app_uuid_from_packet(struct mbuf *packet,
12928 uuid_t app_uuid)
12929 {
12930 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12931 return EINVAL;
12932 }
12933
12934 bool found_mapping = FALSE;
12935 if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
12936 lck_rw_lock_shared(&necp_kernel_policy_lock);
12937 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);
12938 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
12939 if (entry != NULL) {
12940 uuid_copy(app_uuid, entry->uuid);
12941 found_mapping = true;
12942 }
12943 lck_rw_done(&necp_kernel_policy_lock);
12944 }
12945 if (!found_mapping) {
12946 uuid_clear(app_uuid);
12947 }
12948 return 0;
12949 }
12950
12951 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)12952 necp_get_is_keepalive_from_packet(struct mbuf *packet)
12953 {
12954 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12955 return FALSE;
12956 }
12957
12958 return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
12959 }
12960
12961 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)12962 necp_socket_get_content_filter_control_unit(struct socket *so)
12963 {
12964 struct inpcb *inp = sotoinpcb(so);
12965
12966 if (inp == NULL) {
12967 return 0;
12968 }
12969 return inp->inp_policyresult.results.filter_control_unit;
12970 }
12971
12972 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)12973 necp_socket_get_policy_gencount(struct socket *so)
12974 {
12975 struct inpcb *inp = so ? sotoinpcb(so) : NULL;
12976
12977 if (inp == NULL) {
12978 return 0;
12979 }
12980 return inp->inp_policyresult.policy_gencount;
12981 }
12982
12983 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)12984 necp_socket_should_use_flow_divert(struct inpcb *inp)
12985 {
12986 if (inp == NULL) {
12987 return FALSE;
12988 }
12989
12990 return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
12991 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12992 (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
12993 }
12994
12995 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)12996 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
12997 {
12998 if (inp == NULL) {
12999 return 0;
13000 }
13001
13002 if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13003 return 0;
13004 }
13005
13006 if (aggregate_unit != NULL &&
13007 inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13008 *aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13009 }
13010
13011 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13012 return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13013 }
13014
13015 return 0;
13016 }
13017
13018 bool
necp_socket_should_rescope(struct inpcb * inp)13019 necp_socket_should_rescope(struct inpcb *inp)
13020 {
13021 if (inp == NULL) {
13022 return FALSE;
13023 }
13024
13025 return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13026 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13027 }
13028
13029 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13030 necp_socket_get_rescope_if_index(struct inpcb *inp)
13031 {
13032 if (inp == NULL) {
13033 return 0;
13034 }
13035
13036 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13037 return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13038 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13039 return necp_get_primary_direct_interface_index();
13040 }
13041
13042 return 0;
13043 }
13044
13045 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13046 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13047 {
13048 if (inp == NULL) {
13049 return current_mtu;
13050 }
13051
13052 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13053 (inp->inp_flags & INP_BOUND_IF) &&
13054 inp->inp_boundifp) {
13055 u_int bound_interface_index = inp->inp_boundifp->if_index;
13056 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13057
13058 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13059 if (bound_interface_index != tunnel_interface_index) {
13060 ifnet_t tunnel_interface = NULL;
13061
13062 ifnet_head_lock_shared();
13063 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13064 ifnet_head_done();
13065
13066 if (tunnel_interface != NULL) {
13067 u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13068 u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13069 const char ipsec_prefix[] = "ipsec";
13070 if (delegate_tunnel_mtu != 0 &&
13071 strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13072 // For ipsec interfaces, calculate the overhead from the delegate interface
13073 u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13074 if (delegate_tunnel_mtu > tunnel_overhead) {
13075 delegate_tunnel_mtu -= tunnel_overhead;
13076 }
13077
13078 if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13079 // If the (delegate - overhead) < direct, return (delegate - overhead)
13080 return delegate_tunnel_mtu;
13081 } else {
13082 // Otherwise return direct
13083 return direct_tunnel_mtu;
13084 }
13085 } else {
13086 // For non-ipsec interfaces, just return the tunnel MTU
13087 return direct_tunnel_mtu;
13088 }
13089 }
13090 }
13091 }
13092
13093 // By default, just return the MTU passed in
13094 return current_mtu;
13095 }
13096
13097 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13098 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13099 {
13100 if (result_parameter == NULL) {
13101 return NULL;
13102 }
13103
13104 return ifindex2ifnet[result_parameter->tunnel_interface_index];
13105 }
13106
13107 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13108 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13109 {
13110 bool found_match = FALSE;
13111 bool can_rebind = FALSE;
13112 ifaddr_t ifa;
13113 union necp_sockaddr_union address_storage;
13114
13115 if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13116 return FALSE;
13117 }
13118
13119 // Match source address against interface addresses
13120 ifnet_lock_shared(interface);
13121 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13122 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13123 if (address_storage.sa.sa_family != family) {
13124 continue;
13125 }
13126
13127 if (family == AF_INET) {
13128 struct ip *ip = mtod(packet, struct ip *);
13129 if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13130 found_match = TRUE;
13131 break;
13132 }
13133 } else if (family == AF_INET6) {
13134 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13135 if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13136 found_match = TRUE;
13137 break;
13138 }
13139 }
13140 }
13141 }
13142 const uint32_t if_idx = interface->if_index;
13143 ifnet_lock_done(interface);
13144
13145 // If source address matched, attempt to construct a route to the destination address
13146 if (found_match) {
13147 ROUTE_RELEASE(new_route);
13148
13149 if (family == AF_INET) {
13150 struct ip *ip = mtod(packet, struct ip *);
13151 struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13152 dst4->sin_family = AF_INET;
13153 dst4->sin_len = sizeof(struct sockaddr_in);
13154 dst4->sin_addr = ip->ip_dst;
13155 rtalloc_scoped(new_route, if_idx);
13156 if (!ROUTE_UNUSABLE(new_route)) {
13157 can_rebind = TRUE;
13158 }
13159 } else if (family == AF_INET6) {
13160 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13161 struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13162 dst6->sin6_family = AF_INET6;
13163 dst6->sin6_len = sizeof(struct sockaddr_in6);
13164 dst6->sin6_addr = ip6->ip6_dst;
13165 rtalloc_scoped(new_route, if_idx);
13166 if (!ROUTE_UNUSABLE(new_route)) {
13167 can_rebind = TRUE;
13168 }
13169 }
13170 }
13171
13172 return can_rebind;
13173 }
13174
13175 static bool
necp_addr_is_loopback(struct sockaddr * address)13176 necp_addr_is_loopback(struct sockaddr *address)
13177 {
13178 if (address == NULL) {
13179 return FALSE;
13180 }
13181
13182 if (address->sa_family == AF_INET) {
13183 return ntohl(SIN(address)->sin_addr.s_addr) == INADDR_LOOPBACK;
13184 } else if (address->sa_family == AF_INET6) {
13185 if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13186 return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13187 } else {
13188 // Match ::ffff:127.0.0.1 loopback address
13189 in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13190 return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13191 }
13192 }
13193
13194 return FALSE;
13195 }
13196
13197 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)13198 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13199 {
13200 // Note: This function only checks for the loopback addresses.
13201 // In the future, we may want to expand to also allow any traffic
13202 // going through the loopback interface, but until then, this
13203 // check is cheaper.
13204
13205 if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13206 return TRUE;
13207 }
13208
13209 if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13210 return TRUE;
13211 }
13212
13213 if (inp != NULL) {
13214 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13215 return TRUE;
13216 }
13217 if (inp->inp_vflag & INP_IPV4) {
13218 if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
13219 ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
13220 return TRUE;
13221 }
13222 } else if (inp->inp_vflag & INP_IPV6) {
13223 if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13224 IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13225 return TRUE;
13226 }
13227 }
13228 } else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13229 return TRUE;
13230 }
13231
13232 if (packet != NULL) {
13233 struct ip *ip = mtod(packet, struct ip *);
13234 if (ip->ip_v == 4) {
13235 if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
13236 return TRUE;
13237 }
13238 if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
13239 return TRUE;
13240 }
13241 } else if (ip->ip_v == 6) {
13242 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13243 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13244 return TRUE;
13245 }
13246 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13247 return TRUE;
13248 }
13249 }
13250 }
13251
13252 return FALSE;
13253 }
13254
13255 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13256 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13257 {
13258 if (inp != NULL) {
13259 if (!(inp->inp_vflag & INP_IPV6)) {
13260 return false;
13261 }
13262 if (INP_INTCOPROC_ALLOWED(inp)) {
13263 return true;
13264 }
13265 if ((inp->inp_flags & INP_BOUND_IF) &&
13266 IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13267 return true;
13268 }
13269 return false;
13270 }
13271 if (packet != NULL) {
13272 struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13273 struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13274 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13275 NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13276 return true;
13277 }
13278 }
13279
13280 return false;
13281 }
13282
13283 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13284 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13285 {
13286 char dest_str[MAX_IPv6_STR_LEN];
13287
13288 if (necp_drop_dest_debug > 0) {
13289 if (sau->sa.sa_family == AF_INET) {
13290 (void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13291 } else if (sau->sa.sa_family == AF_INET6) {
13292 (void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13293 } else {
13294 dest_str[0] = 0;
13295 }
13296 }
13297 for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13298 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13299 struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13300
13301 if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13302 if (necp_drop_dest_debug > 0) {
13303 char subnet_str[MAX_IPv6_STR_LEN];
13304 struct proc *p = current_proc();
13305 pid_t pid = proc_pid(p);
13306
13307 if (sau->sa.sa_family == AF_INET) {
13308 (void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13309 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);
13310 } else if (sau->sa.sa_family == AF_INET6) {
13311 (void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13312 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);
13313 }
13314 }
13315 return true;
13316 }
13317 }
13318 if (necp_drop_dest_debug > 1) {
13319 struct proc *p = current_proc();
13320 pid_t pid = proc_pid(p);
13321
13322 os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13323 }
13324 return false;
13325 }
13326
13327 static int
13328 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13329 {
13330 #pragma unused(arg1, arg2, oidp)
13331 int changed = 0;
13332 int error = 0;
13333 struct necp_drop_dest_policy tmp_drop_dest_policy;
13334 struct proc *p = current_proc();
13335 pid_t pid = proc_pid(p);
13336
13337 if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13338 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13339 NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13340 return EPERM;
13341 }
13342 if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13343 NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13344 return EINVAL;
13345 }
13346
13347 memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13348 error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13349 if (error != 0) {
13350 NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13351 return error;
13352 }
13353 if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13354 return error;
13355 }
13356
13357 //
13358 // Validate the passed parameters
13359 //
13360 if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13361 NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13362 return EINVAL;
13363 }
13364 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13365 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13366 struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13367
13368 switch (tmp_drop_dest_entry->level) {
13369 case NECP_SESSION_PRIORITY_UNKNOWN:
13370 if (tmp_drop_dest_policy.entry_count != 0) {
13371 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);
13372 return EINVAL;
13373 }
13374 break;
13375 case NECP_SESSION_PRIORITY_CONTROL:
13376 case NECP_SESSION_PRIORITY_CONTROL_1:
13377 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13378 case NECP_SESSION_PRIORITY_HIGH:
13379 case NECP_SESSION_PRIORITY_HIGH_1:
13380 case NECP_SESSION_PRIORITY_HIGH_2:
13381 case NECP_SESSION_PRIORITY_HIGH_3:
13382 case NECP_SESSION_PRIORITY_HIGH_4:
13383 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13384 case NECP_SESSION_PRIORITY_DEFAULT:
13385 case NECP_SESSION_PRIORITY_LOW:
13386 if (tmp_drop_dest_policy.entry_count == 0) {
13387 NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13388 return EINVAL;
13389 }
13390 break;
13391 default: {
13392 NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13393 return EINVAL;
13394 }
13395 }
13396
13397 switch (npca->address.sa.sa_family) {
13398 case AF_INET: {
13399 if (npca->prefix > 32) {
13400 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13401 return EINVAL;
13402 }
13403 if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
13404 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
13405 return EINVAL;
13406 }
13407 if (npca->address.sin.sin_port != 0) {
13408 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);
13409 return EINVAL;
13410 }
13411 break;
13412 }
13413 case AF_INET6: {
13414 if (npca->prefix > 128) {
13415 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13416 return EINVAL;
13417 }
13418 if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
13419 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
13420 return EINVAL;
13421 }
13422 if (npca->address.sin6.sin6_port != 0) {
13423 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);
13424 return EINVAL;
13425 }
13426 if (npca->address.sin6.sin6_flowinfo != 0) {
13427 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);
13428 return EINVAL;
13429 }
13430 if (npca->address.sin6.sin6_scope_id != 0) {
13431 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);
13432 return EINVAL;
13433 }
13434 break;
13435 }
13436 default: {
13437 return EINVAL;
13438 }
13439 }
13440 }
13441
13442 //
13443 // Commit the changed policy
13444 //
13445 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
13446 memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
13447
13448 necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
13449 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13450 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13451 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13452
13453 memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
13454
13455 necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
13456 }
13457 lck_rw_done(&necp_kernel_policy_lock);
13458
13459 return 0;
13460 }
13461
13462 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])13463 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
13464 {
13465 uint16_t fam = address->sa.sa_family;
13466 memset(addr_str, 0, MAX_IPv6_STR_LEN);
13467 if (fam == AF_INET) {
13468 (void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
13469 } else if (fam == AF_INET6) {
13470 (void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
13471 }
13472 return __unsafe_null_terminated_from_indexable(addr_str);
13473 }
13474