1 /*
2 * Copyright (c) 2013-2022 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 && defined(XNU_TARGET_OS_OSX)
62 #include <skywalk/lib/net_filter_event.h>
63 #endif /* defined(SKYWALK) && defined(XNU_TARGET_OS_OSX) */
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 /*
81 * NECP - Network Extension Control Policy database
82 * ------------------------------------------------
83 * The goal of this module is to allow clients connecting via a
84 * policy file descriptor to create high-level policy sessions, which
85 * are ingested into low-level kernel policies that control and tag
86 * traffic at the application, socket, and IP layers.
87 *
88 * ------------------------------------------------
89 * Sessions
90 * ------------------------------------------------
91 * Each session owns a list of session policies, each of which can
92 * specify any combination of conditions and a single result. Each
93 * session also has a priority level (such as High, Default, or Low)
94 * which is requested by the client. Based on the requested level,
95 * a session order value is assigned to the session, which will be used
96 * to sort kernel policies generated by the session. The session client
97 * can specify the sub-order for each policy it creates which will be
98 * used to further sort the kernel policies.
99 *
100 * Policy fd --> 1 necp_session --> list of necp_session_policy structs
101 *
102 * ------------------------------------------------
103 * Kernel Policies
104 * ------------------------------------------------
105 * Whenever a session send the Apply command, its policies are ingested
106 * and generate kernel policies. There are two phases of kernel policy
107 * ingestion.
108 *
109 * 1. The session policy is parsed to create kernel policies at the socket
110 * and IP layers, when applicable. For example, a policy that requires
111 * all traffic from App1 to Pass will generate a socket kernel policy to
112 * match App1 and mark packets with ID1, and also an IP policy to match
113 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
114 * resulting kernel policies are added to the global socket and IP layer
115 * policy lists.
116 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
117 * || ||
118 * \/ \/
119 * necp_kernel_socket_policies necp_kernel_ip_output_policies
120 *
121 * 2. Once the global lists of kernel policies have been filled out, each
122 * list is traversed to create optimized sub-lists ("Maps") which are used during
123 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
124 * which hashes incoming packets based on marked socket-layer policies, and removes
125 * duplicate or overlapping policies. Socket policies are sent into two maps,
126 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
127 * The app layer map is used for policy checks coming in from user space, and is one
128 * list with duplicate and overlapping policies removed. The socket map hashes based
129 * on app UUID, and removes duplicate and overlapping policies.
130 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
131 * |-> necp_kernel_socket_policies_map
132 *
133 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
134 *
135 * ------------------------------------------------
136 * Drop All Level
137 * ------------------------------------------------
138 * The Drop All Level is a sysctl that controls the level at which policies are allowed
139 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
140 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
141 * by a session with a priority level better than (numerically less than) the
142 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
143 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
144 * session orders to be dropped.
145 */
146
147 u_int32_t necp_drop_all_order = 0;
148 u_int32_t necp_drop_all_level = 0;
149
150 u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
151 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
152 u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
153 u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
154 u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
155
156 u_int32_t necp_drop_unentitled_order = 0;
157 #ifdef XNU_TARGET_OS_WATCH
158 u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
159 #else // XNU_TARGET_OS_WATCH
160 u_int32_t necp_drop_unentitled_level = 0;
161 #endif // XNU_TARGET_OS_WATCH
162
163 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
164
165 os_log_t necp_log_handle = NULL;
166 os_log_t necp_data_trace_log_handle = NULL;
167
168 u_int32_t necp_session_count = 0;
169
170 static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
171 struct necp_session_policy, NET_KT_DEFAULT);
172 static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
173 struct necp_kernel_socket_policy, NET_KT_DEFAULT);
174 static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
175 struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
176
177 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
178 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
179 LIST_INSERT_HEAD((head), elm, field); \
180 } else { \
181 LIST_FOREACH(tmpelm, head, field) { \
182 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
183 LIST_INSERT_AFTER(tmpelm, elm, field); \
184 break; \
185 } \
186 } \
187 } \
188 } while (0)
189
190 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
191 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
192 LIST_INSERT_HEAD((head), elm, field); \
193 } else { \
194 LIST_FOREACH(tmpelm, head, field) { \
195 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))) { \
196 LIST_INSERT_AFTER(tmpelm, elm, field); \
197 break; \
198 } \
199 } \
200 } \
201 } while (0)
202
203 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
204 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))) { \
205 LIST_INSERT_HEAD((head), elm, field); \
206 } else { \
207 LIST_FOREACH(tmpelm, head, field) { \
208 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))) { \
209 LIST_INSERT_AFTER(tmpelm, elm, field); \
210 break; \
211 } \
212 } \
213 } \
214 } while (0)
215
216 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x) ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
217
218 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt) \
219 ((rt) != NULL && !((rt)->rt_flags & RTF_GATEWAY) && ((rt)->rt_ifa && (rt)->rt_ifa->ifa_ifp && !((rt)->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT)))
220
221 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x000001
222 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x000002
223 #define NECP_KERNEL_CONDITION_PROTOCOL 0x000004
224 #define NECP_KERNEL_CONDITION_LOCAL_START 0x000008
225 #define NECP_KERNEL_CONDITION_LOCAL_END 0x000010
226 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x000020
227 #define NECP_KERNEL_CONDITION_REMOTE_START 0x000040
228 #define NECP_KERNEL_CONDITION_REMOTE_END 0x000080
229 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x000100
230 #define NECP_KERNEL_CONDITION_APP_ID 0x000200
231 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x000400
232 #define NECP_KERNEL_CONDITION_DOMAIN 0x000800
233 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x001000
234 #define NECP_KERNEL_CONDITION_POLICY_ID 0x002000
235 #define NECP_KERNEL_CONDITION_PID 0x004000
236 #define NECP_KERNEL_CONDITION_UID 0x008000
237 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x010000 // Only set from packets looping between interfaces
238 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x020000
239 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x040000
240 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 0x080000
241 #define NECP_KERNEL_CONDITION_AGENT_TYPE 0x100000
242 #define NECP_KERNEL_CONDITION_HAS_CLIENT 0x200000
243 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS 0x400000
244 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS 0x800000
245 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY 0x1000000
246 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY 0x2000000
247 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY 0x4000000
248 #define NECP_KERNEL_CONDITION_SDK_VERSION 0x8000000
249 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x10000000
250 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 0x20000000
251 #define NECP_KERNEL_CONDITION_IS_LOOPBACK 0x40000000
252 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY 0x80000000
253 #define NECP_KERNEL_CONDITION_SCHEME_PORT 0x100000000
254 #define NECP_KERNEL_CONDITION_DOMAIN_FILTER 0x200000000
255 #define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT 0x400000000
256 #define NECP_KERNEL_CONDITION_EXACT_DOMAIN 0x800000000
257
258
259 #define NECP_MAX_POLICY_RESULT_SIZE 512
260 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
261 #define NECP_MAX_CONDITIONS_ARRAY_SIZE 4096
262 #define NECP_MAX_POLICY_LIST_COUNT 1024
263
264 #define NECP_MAX_DOMAIN_FILTER_SIZE 65536 // Allows room for 100K domains
265
266 typedef enum {
267 NECP_BYPASS_TYPE_NONE = 0,
268 NECP_BYPASS_TYPE_INTCOPROC = 1,
269 NECP_BYPASS_TYPE_LOOPBACK = 2,
270 } necp_socket_bypass_type_t;
271
272 // Cap the policy size at the max result + conditions size, with room for extra TLVs
273 #define NECP_MAX_POLICY_SIZE (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
274
275 struct necp_service_registration {
276 LIST_ENTRY(necp_service_registration) session_chain;
277 LIST_ENTRY(necp_service_registration) kernel_chain;
278 u_int32_t service_id;
279 };
280
281 struct necp_domain_filter {
282 LIST_ENTRY(necp_domain_filter) owner_chain;
283 LIST_ENTRY(necp_domain_filter) chain;
284 u_int32_t id;
285 struct net_bloom_filter *filter;
286 os_refcnt_t refcount;
287 };
288 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
289
290 struct necp_session {
291 u_int8_t necp_fd_type;
292 u_int32_t control_unit;
293 u_int32_t session_priority; // Descriptive priority rating
294 u_int32_t session_order;
295
296 necp_policy_id last_policy_id;
297
298 decl_lck_mtx_data(, lock);
299
300 bool proc_locked; // Messages must come from proc_uuid
301 uuid_t proc_uuid;
302 int proc_pid;
303
304 bool dirty;
305 LIST_HEAD(_policies, necp_session_policy) policies;
306
307 LIST_HEAD(_services, necp_service_registration) services;
308 struct necp_domain_filter_list domain_filters;
309
310 TAILQ_ENTRY(necp_session) chain;
311 };
312
313 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
314 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
315
316 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
317
318 struct necp_socket_info {
319 pid_t pid;
320 int32_t pid_version;
321 uid_t uid;
322 union necp_sockaddr_union local_addr;
323 union necp_sockaddr_union remote_addr;
324 u_int32_t bound_interface_index;
325 u_int32_t traffic_class;
326 u_int16_t protocol;
327 u_int16_t scheme_port;
328 u_int32_t application_id;
329 u_int32_t real_application_id;
330 u_int32_t account_id;
331 u_int32_t drop_order;
332 u_int32_t client_flags;
333 char *domain;
334 unsigned is_entitled : 1;
335 unsigned has_client : 1;
336 unsigned has_system_signed_result : 1;
337 unsigned is_platform_binary : 1;
338 unsigned used_responsible_pid : 1;
339 unsigned is_loopback : 1;
340 unsigned real_is_platform_binary : 1;
341 unsigned is_delegated : 1;
342 unsigned is_local : 1;
343 unsigned __pad_bits : 7;
344 };
345
346 static LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
347 static LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
348 static LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
349 &necp_kernel_policy_mtx_attr);
350
351 static LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
352 static LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
353
354 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
355
356 /*
357 * On modification, invalidate cached lookups by bumping the generation count.
358 * Other calls will need to take the slowpath of taking
359 * the subsystem lock.
360 */
361 static volatile int32_t necp_kernel_socket_policies_gencount;
362 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
363 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
364 necp_kernel_socket_policies_gencount = 1; \
365 } \
366 } while (0)
367
368 /*
369 * Drop-all Bypass:
370 * Allow priviledged processes to bypass the default drop-all
371 * via entitlement check. For OSX, since entitlement check is
372 * not supported for configd, configd signing identity is checked
373 * instead.
374 */
375 #define SIGNING_ID_CONFIGD "com.apple.configd"
376 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
377
378 typedef enum {
379 NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
380 NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
381 NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
382 } necp_drop_all_bypass_check_result_t;
383
384 static u_int64_t necp_kernel_application_policies_condition_mask;
385 static size_t necp_kernel_application_policies_count;
386 static u_int64_t necp_kernel_socket_policies_condition_mask;
387 static size_t necp_kernel_socket_policies_count;
388 static size_t necp_kernel_socket_policies_non_app_count;
389 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
390 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
391 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
392 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
393 static struct necp_kernel_socket_policy **necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
394 static size_t necp_kernel_socket_policies_app_layer_map_count;
395 static struct necp_kernel_socket_policy **necp_kernel_socket_policies_app_layer_map;
396 /*
397 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
398 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
399 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
400 *
401 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
402 */
403
404 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
405 static size_t necp_kernel_ip_output_policies_count;
406 static size_t necp_kernel_ip_output_policies_non_id_count;
407 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
408 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
409 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
410 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
411 static struct necp_kernel_ip_output_policy **necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
412 static struct necp_kernel_socket_policy pass_policy =
413 {
414 .id = NECP_KERNEL_POLICY_ID_NO_MATCH,
415 .result = NECP_KERNEL_POLICY_RESULT_PASS,
416 };
417
418 static struct necp_session *necp_create_session(void);
419 static void necp_delete_session(struct necp_session *session);
420
421 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
422 u_int8_t *tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
423 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
424
425 #define MAX_RESULT_STRING_LEN 64
426 static inline const char * necp_get_result_description(char *result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
427
428 static struct necp_session_policy *necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *conditions_array, u_int32_t conditions_array_size, u_int8_t *route_rules_array, u_int32_t route_rules_array_size, u_int8_t *result, u_int32_t result_size);
429 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
430 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
431 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
432 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
433 static void necp_policy_apply_all(struct necp_session *session);
434
435 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, u_int32_t cond_account_id, char *cond_domain, u_int32_t cond_domain_filter, pid_t cond_pid, int32_t cond_pidversion, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, 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, 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, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
436 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
437 static bool necp_kernel_socket_policies_reprocess(void);
438 static bool necp_kernel_socket_policies_update_uuid_table(void);
439 static inline struct necp_kernel_socket_policy *necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy **policy_search_array, struct necp_socket_info *info, necp_kernel_policy_filter *return_filter, u_int32_t *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 *return_netagent_array, u_int32_t *return_netagent_use_flags_array, size_t netagent_array_count, struct necp_client_parameter_netagent_type *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 *, int debug);
440
441 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, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
442 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
443 static bool necp_kernel_ip_output_policies_reprocess(void);
444
445 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
446 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);
447 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
448 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
449 static bool necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits);
450 static bool necp_addr_is_empty(struct sockaddr *addr);
451 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);
452 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
453
454 struct necp_uuid_id_mapping {
455 LIST_ENTRY(necp_uuid_id_mapping) chain;
456 uuid_t uuid;
457 u_int32_t id;
458 os_refcnt_t refcount;
459 u_int32_t table_usecount; // Add to UUID policy table count
460 };
461 static size_t necp_num_uuid_app_id_mappings;
462 static bool necp_uuid_app_id_mappings_dirty;
463 #define NECP_UUID_APP_ID_HASH_SIZE 64
464 static u_long necp_uuid_app_id_hash_mask;
465 static u_long necp_uuid_app_id_hash_num_buckets;
466 static LIST_HEAD(necp_uuid_id_mapping_head, necp_uuid_id_mapping) * necp_uuid_app_id_hashtbl, necp_uuid_service_id_list; // App map is real hash table, service map is just mapping
467 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
468 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
469 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
470 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
471
472 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
473 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
474 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
475 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
476 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
477
478 struct necp_string_id_mapping {
479 LIST_ENTRY(necp_string_id_mapping) chain;
480 char *string;
481 necp_app_id id;
482 os_refcnt_t refcount;
483 };
484 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
485 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
486 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
487 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
488
489 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);
490 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
491 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
492
493 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
494 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
495
496 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
497
498 static char *necp_create_trimmed_domain(char *string, size_t length);
499 static inline int necp_count_dots(char *string, size_t length);
500
501 static char *necp_copy_string(char *string, size_t length);
502 static bool necp_update_qos_marking(struct ifnet *ifp, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id);
503
504 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
505
506 #define MAX_ROUTE_RULE_INTERFACES 10
507 struct necp_route_rule {
508 LIST_ENTRY(necp_route_rule) chain;
509 u_int32_t id;
510 u_int32_t netagent_id;
511 u_int32_t control_unit;
512 u_int32_t match_netagent_id;
513 u_int8_t default_action;
514 u_int8_t cellular_action;
515 u_int8_t wifi_action;
516 u_int8_t wired_action;
517 u_int8_t expensive_action;
518 u_int8_t constrained_action;
519 u_int8_t companion_action;
520 u_int exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
521 u_int8_t exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
522 os_refcnt_t refcount;
523 };
524 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
525 static u_int32_t necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t *route_rules_array, u_int32_t route_rules_array_size);
526 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
527 static bool necp_route_is_allowed(struct rtentry *route, ifnet_t interface, u_int32_t *netagent_array, size_t netagent_array_count,
528 u_int32_t route_rule_id, u_int32_t *interface_type_denied);
529 static uint32_t necp_route_get_netagent(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove);
530 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
531 static uint32_t necp_route_get_flow_divert(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id);
532 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
533 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
534
535 #define MAX_AGGREGATE_ROUTE_RULES 16
536 struct necp_aggregate_route_rule {
537 LIST_ENTRY(necp_aggregate_route_rule) chain;
538 u_int32_t id;
539 u_int32_t rule_ids[MAX_AGGREGATE_ROUTE_RULES];
540 };
541 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
542 static u_int32_t necp_create_aggregate_route_rule(u_int32_t *rule_ids);
543
544 // Sysctl definitions
545 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
546 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
547
548 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
549 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
550 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
551 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
552 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
553 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
554 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
555 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", "");
556 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", "");
557 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
558 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, "");
559 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
560 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
561
562 static struct necp_drop_dest_policy necp_drop_dest_policy;
563 static int necp_drop_dest_debug = 0; // 0: off, 1: match, >1: every evaluation
564 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
565
566 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
567 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
568 0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
569
570 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
571
572 /*
573 * data tracing control -
574 *
575 * necp_data_tracing_level : 1 for brief trace, 2 for policy details, 3 for condition details
576 * necp_data_tracing_port : match traffic with specified port
577 * necp_data_tracing_proto : match traffic with specified protocol
578 * necp_data_tracing_pid : match traffic with specified pid (only applied at socket level)
579 * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched. Default is 0 to trace traffic if any specified attributes matched.
580 */
581 static int necp_data_tracing_level = 0;
582 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
583
584 static int necp_data_tracing_port = 0;
585 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
586
587 static int necp_data_tracing_proto = 0;
588 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
589
590 static int necp_data_tracing_pid = 0;
591 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
592
593 static int necp_data_tracing_match_all = 0;
594 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
595
596 #define NECP_DATA_TRACE_LEVEL_BRIEF 1
597 #define NECP_DATA_TRACE_LEVEL_POLICY 2
598 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
599
600 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
601 (pid == necp_data_tracing_pid)
602 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
603 (protocol == necp_data_tracing_proto)
604 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
605 (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
606 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
607 (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
608
609 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid) \
610 ((necp_data_tracing_level && \
611 ((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
612 (necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
613 (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)
614
615 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid) \
616 ((necp_data_tracing_level && \
617 ((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
618 (!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
619 (!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)
620
621 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid) \
622 (necp_data_tracing_match_all ? \
623 NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid) : \
624 NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid))
625
626 #define NECP_DATA_TRACE_ON(debug) (debug)
627 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
628 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
629
630 #define NECP_DATA_TRACE_LOG_SOCKET(debug, caller, log_msg, policy_id, skip_policy_id) \
631 if (NECP_DATA_TRACE_ON(debug)) { \
632 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - proto %d port <local %d/%d remote %d/%d> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> <policy_id %d skip_policy_id %d>", \
633 caller, log_msg, 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_drop_all_order, info.pid, info.application_id, info.real_application_id, info.bound_interface_index, policy_id, skip_policy_id); \
634 }
635
636 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
637 if (NECP_DATA_TRACE_ON(debug)) { \
638 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - proto %d port <local %d/%d remote %d/%d> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> (policy id=%d session_order=%d policy_order=%d result=%s)", \
639 caller, (unsigned long long)socket, log_msg, 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_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]); \
640 }
641
642 #define NECP_DATA_TRACE_LOG_IP(debug, caller, log_msg) \
643 if (NECP_DATA_TRACE_ON(debug)) { \
644 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - proto %d port <local %d/%d remote %d/%d > <drop-all order %d> <BoundInterface %d> <socket policy id %d socket skip id %d>", \
645 caller, log_msg, 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_drop_all_order, bound_interface_index, socket_policy_id, socket_skip_policy_id); \
646 }
647
648 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
649 if (NECP_DATA_TRACE_ON(debug)) { \
650 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - proto %d port <local %d/%d remote %d/%d> <drop-all order %d> <BoundInterface %d> (policy id=%d session_order=%d policy_order=%d result=%s)", \
651 caller, log_msg, 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_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]); \
652 }
653
654 #define NECP_DATA_TRACE_LOG_POLICY(debug, caller, log_msg) \
655 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
656 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)", \
657 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); \
658 }
659
660 #define NECP_DATA_TRACE_LOG_CONDITION3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
661 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
662 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)>", \
663 caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
664 }
665
666 #define NECP_DATA_TRACE_LOG_CONDITION_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
667 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
668 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
669 caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
670 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
671 }
672
673 #define NECP_DATA_TRACE_LOG_CONDITION(debug, caller, negate, name, val, input) \
674 NECP_DATA_TRACE_LOG_CONDITION3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
675
676 #define NECP_DATA_TRACE_LOG_CONDITION_STR(debug, caller, negate, name, val, input) \
677 NECP_DATA_TRACE_LOG_CONDITION_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
678
679 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
680 (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
681 addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
682
683 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
684 "INVALID",
685 "PASS",
686 "SKIP",
687 "DROP",
688 "SOCKET_DIVERT",
689 "SOCKET_FILTER",
690 "IP_TUNNEL",
691 "IP_FILTER",
692 "TRIGGER",
693 "TRIGGER_IF_NEEDED",
694 "TRIGGER_SCOPED",
695 "NO_TRIGGER_SCOPED",
696 "SOCKET_SCOPED",
697 "ROUTE_RULES",
698 "USE_NETAGENT",
699 "NETAGENT_SCOPED",
700 "SCOPED_DIRECT",
701 "ALLOW_UNENTITLED",
702 "REMOVE_NETAGENT"
703 };
704
705 // Session order allocation
706 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)707 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
708 {
709 u_int32_t new_order = 0;
710
711 // For now, just allocate 1000 orders for each priority
712 if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
713 priority = NECP_SESSION_PRIORITY_DEFAULT;
714 }
715
716 // Use the control unit to decide the offset into the priority list
717 new_order = (control_unit) + ((priority - 1) * 1000);
718
719 return new_order;
720 }
721
722 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)723 necp_get_first_order_for_priority(u_int32_t priority)
724 {
725 if (priority == 0) {
726 return 0;
727 }
728 return ((priority - 1) * 1000) + 1;
729 }
730
731 // Sysctl handler
732 static int
733 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
734 {
735 #pragma unused(arg1, arg2)
736 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
737 necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
738 return error;
739 }
740
741 static int
742 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
743 {
744 #pragma unused(arg1, arg2)
745 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
746 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
747 return error;
748 }
749
750 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
751 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)752 _necp_process_drop_order_inner(kauth_cred_t cred)
753 {
754 if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
755 priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
756 return necp_drop_unentitled_order;
757 } else {
758 return 0;
759 }
760 }
761
762 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
763 #pragma GCC poison _necp_process_drop_order_inner
764
765 // Session fd
766
767 static int necp_session_op_close(struct fileglob *, vfs_context_t);
768
769 static const struct fileops necp_session_fd_ops = {
770 .fo_type = DTYPE_NETPOLICY,
771 .fo_read = fo_no_read,
772 .fo_write = fo_no_write,
773 .fo_ioctl = fo_no_ioctl,
774 .fo_select = fo_no_select,
775 .fo_close = necp_session_op_close,
776 .fo_drain = fo_no_drain,
777 .fo_kqfilter = fo_no_kqfilter,
778 };
779
780 static inline int
necp_is_platform_binary(proc_t proc)781 necp_is_platform_binary(proc_t proc)
782 {
783 return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
784 }
785
786 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)787 necp_check_drop_all_bypass_result(proc_t proc)
788 {
789 if (proc == NULL) {
790 proc = current_proc();
791 if (proc == NULL) {
792 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
793 }
794 }
795
796 #if defined(XNU_TARGET_OS_OSX)
797 const char *signing_id = NULL;
798 const bool isConfigd = (necp_is_platform_binary(proc) &&
799 (signing_id = cs_identity_get(proc)) &&
800 (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
801 (memcmp(signing_id, SIGNING_ID_CONFIGD, SIGNING_ID_CONFIGD_LEN) == 0));
802 if (isConfigd) {
803 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
804 }
805 #endif
806
807 const task_t task = proc_task(proc);
808 if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
809 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
810 } else {
811 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
812 }
813 }
814
815 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)816 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
817 {
818 #pragma unused(uap)
819 int error = 0;
820 struct necp_session *session = NULL;
821 struct fileproc *fp = NULL;
822 int fd = -1;
823 uid_t uid = kauth_cred_getuid(kauth_cred_get());
824
825 if (!necp_is_platform_binary(p)) {
826 NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
827 error = EACCES;
828 goto done;
829 }
830
831 if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
832 NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
833 error = EACCES;
834 goto done;
835 }
836
837 error = falloc(p, &fp, &fd, vfs_context_current());
838 if (error != 0) {
839 goto done;
840 }
841
842 session = necp_create_session();
843 if (session == NULL) {
844 error = ENOMEM;
845 goto done;
846 }
847
848 fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
849 fp->fp_glob->fg_flag = 0;
850 fp->fp_glob->fg_ops = &necp_session_fd_ops;
851 fp_set_data(fp, session);
852
853 proc_fdlock(p);
854 procfdtbl_releasefd(p, fd, NULL);
855 fp_drop(p, fd, fp, 1);
856 proc_fdunlock(p);
857
858 *retval = fd;
859 done:
860 if (error != 0) {
861 if (fp != NULL) {
862 fp_free(p, fd, fp);
863 fp = NULL;
864 }
865 }
866
867 return error;
868 }
869
870 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)871 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
872 {
873 #pragma unused(ctx)
874 struct necp_session *session = (struct necp_session *)fg_get_data(fg);
875 fg_set_data(fg, NULL);
876
877 if (session != NULL) {
878 necp_policy_mark_all_for_deletion(session);
879 necp_policy_apply_all(session);
880 necp_delete_session(session);
881 return 0;
882 } else {
883 return ENOENT;
884 }
885 }
886
887 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)888 necp_session_find_from_fd(struct proc *p, int fd,
889 struct fileproc **fpp, struct necp_session **session)
890 {
891 struct fileproc *fp = NULL;
892 int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
893
894 if (error == 0) {
895 *fpp = fp;
896 *session = (struct necp_session *)fp_get_data(fp);
897 if ((*session)->necp_fd_type != necp_fd_type_session) {
898 // Not a client fd, ignore
899 fp_drop(p, fd, fp, 0);
900 error = EINVAL;
901 }
902 }
903
904 return error;
905 }
906
907 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)908 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
909 {
910 int error = 0;
911 u_int8_t *tlv_buffer = NULL;
912
913 if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
914 NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
915 error = EINVAL;
916 goto done;
917 }
918
919 if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
920 NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
921 error = EINVAL;
922 goto done;
923 }
924
925 if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
926 error = ENOMEM;
927 goto done;
928 }
929
930 error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
931 if (error != 0) {
932 NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
933 goto done;
934 }
935
936 necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
937 if (error != 0) {
938 NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
939 goto done;
940 }
941
942 error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
943 if (error != 0) {
944 NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
945 goto done;
946 }
947
948 done:
949 if (tlv_buffer != NULL) {
950 kfree_data(tlv_buffer, uap->in_buffer_length);
951 tlv_buffer = NULL;
952 }
953 *retval = error;
954
955 return error;
956 }
957
958 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)959 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
960 {
961 int error = 0;
962 u_int8_t *response = NULL;
963
964 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
965 NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
966 error = EINVAL;
967 goto done;
968 }
969
970 necp_policy_id policy_id = 0;
971 error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
972 if (error != 0) {
973 NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
974 goto done;
975 }
976
977 struct necp_session_policy *policy = necp_policy_find(session, policy_id);
978 if (policy == NULL || policy->pending_deletion) {
979 NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
980 error = ENOENT;
981 goto done;
982 }
983
984 u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
985 u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
986 u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
987
988 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
989 NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
990 error = EINVAL;
991 goto done;
992 }
993
994 if (response_size > NECP_MAX_POLICY_SIZE) {
995 NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
996 error = EINVAL;
997 goto done;
998 }
999
1000 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1001 if (response == NULL) {
1002 error = ENOMEM;
1003 goto done;
1004 }
1005
1006 u_int8_t *cursor = response;
1007 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1008 if (result_tlv_size) {
1009 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, &policy->result, response, response_size);
1010 }
1011 if (policy->conditions_size) {
1012 memcpy(((u_int8_t *)(void *)(cursor)), policy->conditions, policy->conditions_size);
1013 }
1014
1015 error = copyout(response, uap->out_buffer, response_size);
1016 if (error != 0) {
1017 NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1018 goto done;
1019 }
1020
1021 done:
1022 if (response != NULL) {
1023 kfree_data(response, response_size);
1024 response = NULL;
1025 }
1026 *retval = error;
1027
1028 return error;
1029 }
1030
1031 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1032 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1033 {
1034 int error = 0;
1035
1036 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1037 NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1038 error = EINVAL;
1039 goto done;
1040 }
1041
1042 necp_policy_id delete_policy_id = 0;
1043 error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1044 if (error != 0) {
1045 NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1046 goto done;
1047 }
1048
1049 struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1050 if (policy == NULL || policy->pending_deletion) {
1051 NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1052 error = ENOENT;
1053 goto done;
1054 }
1055
1056 necp_policy_mark_for_deletion(session, policy);
1057 done:
1058 *retval = error;
1059 return error;
1060 }
1061
1062 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1063 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1064 {
1065 #pragma unused(uap)
1066 necp_policy_apply_all(session);
1067 *retval = 0;
1068 return 0;
1069 }
1070
1071 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1072 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1073 {
1074 u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1075 u_int32_t response_size = 0;
1076 u_int8_t *response = NULL;
1077 int num_policies = 0;
1078 int cur_policy_index = 0;
1079 int error = 0;
1080 struct necp_session_policy *policy;
1081
1082 LIST_FOREACH(policy, &session->policies, chain) {
1083 if (!policy->pending_deletion) {
1084 num_policies++;
1085 }
1086 }
1087
1088 if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1089 NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1090 error = EINVAL;
1091 goto done;
1092 }
1093
1094 response_size = num_policies * tlv_size;
1095 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1096 NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1097 error = EINVAL;
1098 goto done;
1099 }
1100
1101 // Create a response with one Policy ID TLV for each policy
1102 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1103 if (response == NULL) {
1104 error = ENOMEM;
1105 goto done;
1106 }
1107
1108 u_int8_t *cursor = response;
1109 LIST_FOREACH(policy, &session->policies, chain) {
1110 if (!policy->pending_deletion && cur_policy_index < num_policies) {
1111 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1112 cur_policy_index++;
1113 }
1114 }
1115
1116 error = copyout(response, uap->out_buffer, response_size);
1117 if (error != 0) {
1118 NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1119 goto done;
1120 }
1121
1122 done:
1123 if (response != NULL) {
1124 kfree_data(response, response_size);
1125 response = NULL;
1126 }
1127 *retval = error;
1128
1129 return error;
1130 }
1131
1132
1133 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1134 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1135 {
1136 #pragma unused(uap)
1137 necp_policy_mark_all_for_deletion(session);
1138 *retval = 0;
1139 return 0;
1140 }
1141
1142 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1143 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1144 {
1145 int error = 0;
1146 struct necp_session_policy *policy = NULL;
1147 struct necp_session_policy *temp_policy = NULL;
1148
1149 if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1150 NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1151 error = EINVAL;
1152 goto done;
1153 }
1154
1155 necp_session_priority requested_session_priority = 0;
1156 error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1157 if (error != 0) {
1158 NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1159 goto done;
1160 }
1161
1162 // Enforce special session priorities with entitlements
1163 if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1164 requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1165 requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1166 requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1167 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1168 if (cred_result != 0) {
1169 NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1170 error = EPERM;
1171 goto done;
1172 }
1173 }
1174
1175 if (session->session_priority != requested_session_priority) {
1176 session->session_priority = requested_session_priority;
1177 session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1178 session->dirty = TRUE;
1179
1180 // Mark all policies as needing updates
1181 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1182 policy->pending_update = TRUE;
1183 }
1184 }
1185
1186 done:
1187 *retval = error;
1188 return error;
1189 }
1190
1191 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1192 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1193 {
1194 #pragma unused(uap)
1195 session->proc_locked = TRUE;
1196 *retval = 0;
1197 return 0;
1198 }
1199
1200 static int
necp_session_register_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1201 necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1202 {
1203 int error = 0;
1204 struct necp_service_registration *new_service = NULL;
1205
1206 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1207 NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1208 error = EINVAL;
1209 goto done;
1210 }
1211
1212 uuid_t service_uuid;
1213 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1214 if (error != 0) {
1215 NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1216 goto done;
1217 }
1218
1219 new_service = kalloc_type(struct necp_service_registration,
1220 Z_WAITOK | Z_ZERO | Z_NOFAIL);
1221
1222 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1223 new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1224 LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1225 LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1226 lck_rw_done(&necp_kernel_policy_lock);
1227
1228 done:
1229 *retval = error;
1230 return error;
1231 }
1232
1233 static int
necp_session_unregister_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1234 necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1235 {
1236 int error = 0;
1237 struct necp_service_registration *service = NULL;
1238 struct necp_service_registration *temp_service = NULL;
1239 struct necp_uuid_id_mapping *mapping = NULL;
1240
1241 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1242 NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1243 error = EINVAL;
1244 goto done;
1245 }
1246
1247 uuid_t service_uuid;
1248 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1249 if (error != 0) {
1250 NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1251 goto done;
1252 }
1253
1254 // Remove all matching services for this session
1255 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1256 mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1257 if (mapping != NULL) {
1258 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1259 if (service->service_id == mapping->id) {
1260 LIST_REMOVE(service, session_chain);
1261 LIST_REMOVE(service, kernel_chain);
1262 kfree_type(struct necp_service_registration, service);
1263 }
1264 }
1265 necp_remove_uuid_service_id_mapping(service_uuid);
1266 }
1267 lck_rw_done(&necp_kernel_policy_lock);
1268
1269 done:
1270 *retval = error;
1271 return error;
1272 }
1273
1274 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1275 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1276 {
1277 #pragma unused(session)
1278 int error = 0;
1279
1280 if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1281 NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1282 error = EINVAL;
1283 goto done;
1284 }
1285
1286 error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1287 done:
1288 *retval = error;
1289 return error;
1290 }
1291
1292 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1293 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1294 {
1295 int error = 0;
1296 struct net_bloom_filter *bloom_filter = NULL;
1297 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1298 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1299
1300 if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1301 in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1302 uap->in_buffer == 0) {
1303 NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1304 error = EINVAL;
1305 goto done;
1306 }
1307
1308 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1309 NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1310 error = EINVAL;
1311 goto done;
1312 }
1313
1314 bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1315 if (bloom_filter == NULL) {
1316 NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1317 error = ENOMEM;
1318 goto done;
1319 }
1320
1321 error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1322 if (error != 0) {
1323 NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1324 goto done;
1325 }
1326
1327 size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1328 if (expected_filter_size != in_buffer_length) {
1329 NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1330 error = EINVAL;
1331 goto done;
1332 }
1333
1334 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1335 u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1336 lck_rw_done(&necp_kernel_policy_lock);
1337
1338 if (filter_id == 0) {
1339 error = ENOMEM;
1340 } else {
1341 // Bloom filter is taken over by the new filter entry, clear the local pointer
1342 bloom_filter = NULL;
1343
1344 error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1345 if (error != 0) {
1346 NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1347 goto done;
1348 }
1349 }
1350
1351 done:
1352 *retval = error;
1353 if (error != 0 && bloom_filter != NULL) {
1354 uint8_t *filter_buffer = (uint8_t *)bloom_filter;
1355 kfree_data(filter_buffer, in_buffer_length);
1356 bloom_filter = NULL;
1357 }
1358 return error;
1359 }
1360
1361 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1362 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1363 {
1364 int error = 0;
1365
1366 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1367 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1368 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1369 error = EINVAL;
1370 goto done;
1371 }
1372
1373 u_int32_t filter_id;
1374 error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1375 if (error != 0) {
1376 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1377 goto done;
1378 }
1379
1380 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1381 bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1382 if (!removed) {
1383 error = ENOENT;
1384 }
1385 lck_rw_done(&necp_kernel_policy_lock);
1386
1387 done:
1388 *retval = error;
1389 return error;
1390 }
1391
1392 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1393 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1394 {
1395 #pragma unused(uap)
1396
1397 struct necp_domain_filter *filter = NULL;
1398 struct necp_domain_filter *temp_filter = NULL;
1399 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1400 if (os_ref_release_locked(&filter->refcount) == 0) {
1401 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1402 LIST_REMOVE(filter, chain);
1403 lck_rw_done(&necp_kernel_policy_lock);
1404 LIST_REMOVE(filter, owner_chain);
1405 net_bloom_filter_destroy(filter->filter);
1406 kfree_type(struct necp_domain_filter, filter);
1407 }
1408 }
1409
1410 *retval = 0;
1411 return 0;
1412 }
1413
1414 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1415 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1416 {
1417 struct fileproc *fp;
1418 int error = 0;
1419 int return_value = 0;
1420 struct necp_session *session = NULL;
1421
1422 error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1423 if (error != 0) {
1424 NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1425 return error;
1426 }
1427
1428 NECP_SESSION_LOCK(session);
1429
1430 if (session->proc_locked) {
1431 // Verify that the calling process is allowed to do actions
1432 uuid_t proc_uuid;
1433 proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1434 if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1435 error = EPERM;
1436 goto done;
1437 }
1438 } else {
1439 // If not locked, update the proc_uuid and proc_pid of the session
1440 proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1441 session->proc_pid = proc_pid(current_proc());
1442 }
1443
1444 u_int32_t action = uap->action;
1445 switch (action) {
1446 case NECP_SESSION_ACTION_POLICY_ADD: {
1447 return_value = necp_session_add_policy(session, uap, retval);
1448 break;
1449 }
1450 case NECP_SESSION_ACTION_POLICY_GET: {
1451 return_value = necp_session_get_policy(session, uap, retval);
1452 break;
1453 }
1454 case NECP_SESSION_ACTION_POLICY_DELETE: {
1455 return_value = necp_session_delete_policy(session, uap, retval);
1456 break;
1457 }
1458 case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1459 return_value = necp_session_apply_all(session, uap, retval);
1460 break;
1461 }
1462 case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1463 return_value = necp_session_list_all(session, uap, retval);
1464 break;
1465 }
1466 case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1467 return_value = necp_session_delete_all(session, uap, retval);
1468 break;
1469 }
1470 case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1471 return_value = necp_session_set_session_priority(session, uap, retval);
1472 break;
1473 }
1474 case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1475 return_value = necp_session_lock_to_process(session, uap, retval);
1476 break;
1477 }
1478 case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1479 return_value = necp_session_register_service(session, uap, retval);
1480 break;
1481 }
1482 case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1483 return_value = necp_session_unregister_service(session, uap, retval);
1484 break;
1485 }
1486 case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1487 return_value = necp_session_dump_all(session, uap, retval);
1488 break;
1489 }
1490 case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1491 return_value = necp_session_add_domain_filter(session, uap, retval);
1492 break;
1493 }
1494 case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1495 return_value = necp_session_remove_domain_filter(session, uap, retval);
1496 break;
1497 }
1498 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1499 return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1500 break;
1501 }
1502 default: {
1503 NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1504 return_value = EINVAL;
1505 break;
1506 }
1507 }
1508
1509 done:
1510 NECP_SESSION_UNLOCK(session);
1511 fp_drop(p, uap->necp_fd, fp, 0);
1512 return return_value;
1513 }
1514
1515 struct necp_resolver_key_state {
1516 const struct ccdigest_info *digest_info;
1517 uint8_t key[CCSHA256_OUTPUT_SIZE];
1518 };
1519 static struct necp_resolver_key_state s_necp_resolver_key_state;
1520
1521 static void
necp_generate_resolver_key(void)1522 necp_generate_resolver_key(void)
1523 {
1524 s_necp_resolver_key_state.digest_info = ccsha256_di();
1525 cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1526 }
1527
1528 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)1529 necp_sign_update_context(const struct ccdigest_info *di,
1530 cchmac_ctx_t ctx,
1531 uuid_t client_id,
1532 u_int32_t sign_type,
1533 u_int8_t *data,
1534 size_t data_length)
1535 {
1536 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1537 const char *context_string = "NECP Resolver Binder";
1538 uint8_t separator = 0;
1539 cchmac_update(di, ctx, sizeof(context), context);
1540 cchmac_update(di, ctx, strlen(context_string), context_string);
1541 cchmac_update(di, ctx, sizeof(separator), &separator);
1542 cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1543 cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1544 cchmac_update(di, ctx, data_length, data);
1545 }
1546
1547 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)1548 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1549 u_int8_t *data, size_t data_length,
1550 u_int8_t *tag, size_t *out_tag_length)
1551 {
1552 if (s_necp_resolver_key_state.digest_info == NULL) {
1553 return EINVAL;
1554 }
1555
1556 if (data == NULL ||
1557 data_length == 0 ||
1558 tag == NULL ||
1559 out_tag_length == NULL) {
1560 return EINVAL;
1561 }
1562
1563 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1564 if (*out_tag_length < required_tag_length) {
1565 return ERANGE;
1566 }
1567
1568 *out_tag_length = required_tag_length;
1569
1570 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1571 s_necp_resolver_key_state.digest_info->block_size, ctx);
1572 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1573 sizeof(s_necp_resolver_key_state.key),
1574 s_necp_resolver_key_state.key);
1575 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1576 ctx, client_id, sign_type, data, data_length);
1577 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1578
1579 return 0;
1580 }
1581
1582 bool
necp_validate_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 tag_length)1583 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1584 u_int8_t *data, size_t data_length,
1585 u_int8_t *tag, size_t tag_length)
1586 {
1587 if (s_necp_resolver_key_state.digest_info == NULL) {
1588 return false;
1589 }
1590
1591 if (data == NULL ||
1592 data_length == 0 ||
1593 tag == NULL ||
1594 tag_length == 0) {
1595 return false;
1596 }
1597
1598 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1599 if (tag_length != required_tag_length) {
1600 return false;
1601 }
1602
1603 uint8_t actual_tag[required_tag_length];
1604
1605 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1606 s_necp_resolver_key_state.digest_info->block_size, ctx);
1607 cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1608 sizeof(s_necp_resolver_key_state.key),
1609 s_necp_resolver_key_state.key);
1610 necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1611 ctx, client_id, sign_type, data, data_length);
1612 cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
1613
1614 return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
1615 }
1616
1617 void
necp_init(void)1618 necp_init(void)
1619 {
1620 necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
1621 necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
1622
1623 necp_client_init();
1624
1625 TAILQ_INIT(&necp_session_list);
1626
1627 LIST_INIT(&necp_kernel_socket_policies);
1628 LIST_INIT(&necp_kernel_ip_output_policies);
1629
1630 LIST_INIT(&necp_account_id_list);
1631
1632 LIST_INIT(&necp_uuid_service_id_list);
1633
1634 LIST_INIT(&necp_registered_service_list);
1635
1636 LIST_INIT(&necp_route_rules);
1637 LIST_INIT(&necp_aggregate_route_rules);
1638
1639 LIST_INIT(&necp_global_domain_filter_list);
1640
1641 necp_generate_resolver_key();
1642
1643 necp_uuid_app_id_hashtbl = hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask);
1644 necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
1645 necp_num_uuid_app_id_mappings = 0;
1646 necp_uuid_app_id_mappings_dirty = FALSE;
1647
1648 necp_kernel_application_policies_condition_mask = 0;
1649 necp_kernel_socket_policies_condition_mask = 0;
1650 necp_kernel_ip_output_policies_condition_mask = 0;
1651
1652 necp_kernel_application_policies_count = 0;
1653 necp_kernel_socket_policies_count = 0;
1654 necp_kernel_socket_policies_non_app_count = 0;
1655 necp_kernel_ip_output_policies_count = 0;
1656 necp_kernel_ip_output_policies_non_id_count = 0;
1657
1658 necp_kernel_socket_policies_gencount = 1;
1659
1660 memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
1661 memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
1662 necp_kernel_socket_policies_app_layer_map = NULL;
1663
1664 necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
1665 }
1666
1667 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)1668 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
1669 {
1670 struct kev_msg ev_msg;
1671 memset(&ev_msg, 0, sizeof(ev_msg));
1672
1673 ev_msg.vendor_code = KEV_VENDOR_APPLE;
1674 ev_msg.kev_class = KEV_NETWORK_CLASS;
1675 ev_msg.kev_subclass = KEV_NECP_SUBCLASS;
1676 ev_msg.event_code = KEV_NECP_POLICIES_CHANGED;
1677
1678 ev_msg.dv[0].data_ptr = necp_event_data;
1679 ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
1680 ev_msg.dv[1].data_length = 0;
1681
1682 kev_post_msg(&ev_msg);
1683 }
1684
1685 static inline bool
necp_buffer_write_tlv_validate(u_int8_t * cursor,u_int8_t type,u_int32_t length,u_int8_t * buffer,u_int32_t buffer_length)1686 necp_buffer_write_tlv_validate(u_int8_t *cursor, u_int8_t type, u_int32_t length,
1687 u_int8_t *buffer, u_int32_t buffer_length)
1688 {
1689 if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
1690 NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
1691 return false;
1692 }
1693 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1694 if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
1695 (uintptr_t)(next_tlv - buffer) > buffer_length) { // make sure the next TLV has enough room in buffer
1696 NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
1697 length, buffer_length);
1698 return false;
1699 }
1700 return true;
1701 }
1702
1703 u_int8_t *
necp_buffer_write_tlv_if_different(u_int8_t * cursor,u_int8_t type,u_int32_t length,const void * value,bool * updated,u_int8_t * buffer,u_int32_t buffer_length)1704 necp_buffer_write_tlv_if_different(u_int8_t *cursor, u_int8_t type,
1705 u_int32_t length, const void *value, bool *updated,
1706 u_int8_t *buffer, u_int32_t buffer_length)
1707 {
1708 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
1709 // If we can't fit this TLV, return the current cursor
1710 return cursor;
1711 }
1712 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1713 if (*updated || *(u_int8_t *)(cursor) != type) {
1714 *(u_int8_t *)(cursor) = type;
1715 *updated = TRUE;
1716 }
1717 if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
1718 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
1719 *updated = TRUE;
1720 }
1721 if (length > 0) {
1722 if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
1723 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
1724 *updated = TRUE;
1725 }
1726 }
1727 return next_tlv;
1728 }
1729
1730 u_int8_t *
necp_buffer_write_tlv(u_int8_t * cursor,u_int8_t type,u_int32_t length,const void * value,u_int8_t * buffer,u_int32_t buffer_length)1731 necp_buffer_write_tlv(u_int8_t *cursor, u_int8_t type,
1732 u_int32_t length, const void *value,
1733 u_int8_t *buffer, u_int32_t buffer_length)
1734 {
1735 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
1736 return NULL;
1737 }
1738 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1739 *(u_int8_t *)(cursor) = type;
1740 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
1741 if (length > 0) {
1742 memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
1743 }
1744
1745 return next_tlv;
1746 }
1747
1748 u_int8_t
necp_buffer_get_tlv_type(u_int8_t * buffer,int tlv_offset)1749 necp_buffer_get_tlv_type(u_int8_t *buffer, int tlv_offset)
1750 {
1751 u_int8_t *type = NULL;
1752
1753 if (buffer == NULL) {
1754 return 0;
1755 }
1756
1757 type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
1758 return type ? *type : 0;
1759 }
1760
1761 u_int32_t
necp_buffer_get_tlv_length(u_int8_t * buffer,int tlv_offset)1762 necp_buffer_get_tlv_length(u_int8_t *buffer, int tlv_offset)
1763 {
1764 u_int32_t *length = NULL;
1765
1766 if (buffer == NULL) {
1767 return 0;
1768 }
1769
1770 length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
1771 return length ? *length : 0;
1772 }
1773
1774 u_int8_t *
necp_buffer_get_tlv_value(u_int8_t * buffer,int tlv_offset,u_int32_t * value_size)1775 necp_buffer_get_tlv_value(u_int8_t *buffer, int tlv_offset, u_int32_t *value_size)
1776 {
1777 u_int8_t *value = NULL;
1778 u_int32_t length = necp_buffer_get_tlv_length(buffer, tlv_offset);
1779 if (length == 0) {
1780 return value;
1781 }
1782
1783 if (value_size) {
1784 *value_size = length;
1785 }
1786
1787 value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
1788 return value;
1789 }
1790
1791 int
necp_buffer_find_tlv(u_int8_t * buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)1792 necp_buffer_find_tlv(u_int8_t *buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
1793 {
1794 if (err != NULL) {
1795 *err = ENOENT;
1796 }
1797 if (offset < 0) {
1798 if (err != NULL) {
1799 *err = EINVAL;
1800 }
1801 return -1;
1802 }
1803 int cursor = offset;
1804 int next_cursor;
1805 u_int32_t curr_length;
1806 u_int8_t curr_type;
1807
1808 while (TRUE) {
1809 if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
1810 return -1;
1811 }
1812 if (!next) {
1813 curr_type = necp_buffer_get_tlv_type(buffer, cursor);
1814 } else {
1815 next = 0;
1816 curr_type = NECP_TLV_NIL;
1817 }
1818 curr_length = necp_buffer_get_tlv_length(buffer, cursor);
1819 if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
1820 return -1;
1821 }
1822
1823 next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
1824 if (curr_type == type) {
1825 // check if entire TLV fits inside buffer
1826 if (((u_int32_t)next_cursor) <= buffer_length) {
1827 if (err != NULL) {
1828 *err = 0;
1829 }
1830 return cursor;
1831 } else {
1832 return -1;
1833 }
1834 }
1835 cursor = next_cursor;
1836 }
1837 }
1838
1839 static int
necp_find_tlv(u_int8_t * buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)1840 necp_find_tlv(u_int8_t *buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
1841 {
1842 int cursor = -1;
1843 if (buffer != NULL) {
1844 cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
1845 }
1846 return cursor;
1847 }
1848
1849 static int
necp_get_tlv_at_offset(u_int8_t * buffer,u_int32_t buffer_length,int tlv_offset,u_int32_t out_buffer_length,void * out_buffer,u_int32_t * value_size)1850 necp_get_tlv_at_offset(u_int8_t *buffer, u_int32_t buffer_length,
1851 int tlv_offset, u_int32_t out_buffer_length, void *out_buffer, u_int32_t *value_size)
1852 {
1853 if (buffer == NULL) {
1854 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
1855 return EINVAL;
1856 }
1857
1858 // Handle buffer parsing
1859
1860 // Validate that buffer has enough room for any TLV
1861 if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
1862 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
1863 buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
1864 return EINVAL;
1865 }
1866
1867 // Validate that buffer has enough room for this TLV
1868 u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, tlv_offset);
1869 if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
1870 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
1871 tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
1872 return EINVAL;
1873 }
1874
1875 if (out_buffer != NULL && out_buffer_length > 0) {
1876 // Validate that out buffer is large enough for value
1877 if (out_buffer_length < tlv_length) {
1878 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
1879 out_buffer_length, tlv_length);
1880 return EINVAL;
1881 }
1882
1883 // Get value pointer
1884 u_int8_t *tlv_value = necp_buffer_get_tlv_value(buffer, tlv_offset, NULL);
1885 if (tlv_value == NULL) {
1886 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
1887 return ENOENT;
1888 }
1889
1890 // Copy value
1891 memcpy(out_buffer, tlv_value, tlv_length);
1892 }
1893
1894 // Copy out length
1895 if (value_size != NULL) {
1896 *value_size = tlv_length;
1897 }
1898
1899 return 0;
1900 }
1901
1902 static int
necp_get_tlv(u_int8_t * buffer,u_int32_t buffer_length,int offset,u_int8_t type,u_int32_t buff_len,void * buff,u_int32_t * value_size)1903 necp_get_tlv(u_int8_t *buffer, u_int32_t buffer_length,
1904 int offset, u_int8_t type, u_int32_t buff_len, void *buff, u_int32_t *value_size)
1905 {
1906 int error = 0;
1907
1908 int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
1909 if (tlv_offset < 0) {
1910 return error;
1911 }
1912
1913 return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
1914 }
1915
1916 // Session Management
1917
1918 static struct necp_session *
necp_create_session(void)1919 necp_create_session(void)
1920 {
1921 struct necp_session *new_session = NULL;
1922
1923 new_session = kalloc_type(struct necp_session,
1924 Z_WAITOK | Z_ZERO | Z_NOFAIL);
1925
1926 new_session->necp_fd_type = necp_fd_type_session;
1927 new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
1928 new_session->dirty = FALSE;
1929 LIST_INIT(&new_session->policies);
1930 LIST_INIT(&new_session->services);
1931 LIST_INIT(&new_session->domain_filters);
1932 lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
1933
1934 // Take the lock
1935 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1936
1937 // Find the next available control unit
1938 u_int32_t control_unit = 1;
1939 struct necp_session *next_session = NULL;
1940 TAILQ_FOREACH(next_session, &necp_session_list, chain) {
1941 if (next_session->control_unit > control_unit) {
1942 // Found a gap, grab this control unit
1943 break;
1944 }
1945
1946 // Try the next control unit, loop around
1947 control_unit = next_session->control_unit + 1;
1948 }
1949
1950 new_session->control_unit = control_unit;
1951 new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
1952
1953 if (next_session != NULL) {
1954 TAILQ_INSERT_BEFORE(next_session, new_session, chain);
1955 } else {
1956 TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
1957 }
1958
1959 necp_session_count++;
1960 lck_rw_done(&necp_kernel_policy_lock);
1961
1962 if (necp_debug) {
1963 NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
1964 }
1965
1966 return new_session;
1967 }
1968
1969 static void
necp_delete_session(struct necp_session * session)1970 necp_delete_session(struct necp_session *session)
1971 {
1972 if (session != NULL) {
1973 struct necp_service_registration *service = NULL;
1974 struct necp_service_registration *temp_service = NULL;
1975 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1976 LIST_REMOVE(service, session_chain);
1977 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1978 LIST_REMOVE(service, kernel_chain);
1979 lck_rw_done(&necp_kernel_policy_lock);
1980 kfree_type(struct necp_service_registration, service);
1981 }
1982 struct necp_domain_filter *filter = NULL;
1983 struct necp_domain_filter *temp_filter = NULL;
1984 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1985 if (os_ref_release_locked(&filter->refcount) == 0) {
1986 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1987 LIST_REMOVE(filter, chain);
1988 lck_rw_done(&necp_kernel_policy_lock);
1989 LIST_REMOVE(filter, owner_chain);
1990 net_bloom_filter_destroy(filter->filter);
1991 kfree_type(struct necp_domain_filter, filter);
1992 }
1993 }
1994 if (necp_debug) {
1995 NECPLOG0(LOG_DEBUG, "Deleted NECP session");
1996 }
1997
1998 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1999 TAILQ_REMOVE(&necp_session_list, session, chain);
2000 necp_session_count--;
2001 lck_rw_done(&necp_kernel_policy_lock);
2002
2003 lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2004 kfree_type(struct necp_session, session);
2005 }
2006 }
2007
2008 // Session Policy Management
2009
2010 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * buffer,u_int32_t length)2011 necp_policy_result_get_type_from_buffer(u_int8_t *buffer, u_int32_t length)
2012 {
2013 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2014 }
2015
2016 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * buffer,u_int32_t length)2017 necp_policy_result_get_parameter_length_from_buffer(u_int8_t *buffer, u_int32_t length)
2018 {
2019 return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2020 }
2021
2022 static inline u_int8_t *
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * buffer,u_int32_t length)2023 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t *buffer, u_int32_t length)
2024 {
2025 return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2026 }
2027
2028 static bool
necp_policy_result_requires_route_rules(u_int8_t * buffer,u_int32_t length)2029 necp_policy_result_requires_route_rules(u_int8_t *buffer, u_int32_t length)
2030 {
2031 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2032 if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2033 return TRUE;
2034 }
2035 return FALSE;
2036 }
2037
2038 static inline bool
_necp_address_is_valid(struct sockaddr * address)2039 _necp_address_is_valid(struct sockaddr *address)
2040 {
2041 if (address->sa_family == AF_INET) {
2042 return address->sa_len == sizeof(struct sockaddr_in);
2043 } else if (address->sa_family == AF_INET6) {
2044 return address->sa_len == sizeof(struct sockaddr_in6);
2045 } else {
2046 return FALSE;
2047 }
2048 }
2049
2050 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2051
2052 static bool
necp_policy_result_is_valid(u_int8_t * buffer,u_int32_t length,bool * is_pass_skip)2053 necp_policy_result_is_valid(u_int8_t *buffer, u_int32_t length, bool *is_pass_skip)
2054 {
2055 bool validated = FALSE;
2056 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2057 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2058 *is_pass_skip = FALSE;
2059 switch (type) {
2060 case NECP_POLICY_RESULT_PASS: {
2061 *is_pass_skip = TRUE;
2062 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2063 validated = TRUE;
2064 }
2065 break;
2066 }
2067 case NECP_POLICY_RESULT_DROP: {
2068 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2069 validated = TRUE;
2070 }
2071 break;
2072 }
2073 case NECP_POLICY_RESULT_ROUTE_RULES:
2074 case NECP_POLICY_RESULT_SCOPED_DIRECT:
2075 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2076 validated = TRUE;
2077 break;
2078 }
2079 case NECP_POLICY_RESULT_SKIP:
2080 *is_pass_skip = TRUE;
2081 case NECP_POLICY_RESULT_SOCKET_DIVERT:
2082 case NECP_POLICY_RESULT_SOCKET_FILTER: {
2083 if (parameter_length >= sizeof(u_int32_t)) {
2084 validated = TRUE;
2085 }
2086 break;
2087 }
2088 case NECP_POLICY_RESULT_IP_TUNNEL: {
2089 if (parameter_length > sizeof(u_int32_t)) {
2090 validated = TRUE;
2091 }
2092 break;
2093 }
2094 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2095 if (parameter_length > 0) {
2096 validated = TRUE;
2097 }
2098 break;
2099 }
2100 case NECP_POLICY_RESULT_USE_NETAGENT:
2101 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2102 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2103 if (parameter_length >= sizeof(uuid_t)) {
2104 validated = TRUE;
2105 }
2106 break;
2107 }
2108 default: {
2109 validated = FALSE;
2110 break;
2111 }
2112 }
2113
2114 if (necp_debug) {
2115 NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2116 }
2117
2118 return validated;
2119 }
2120
2121 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * buffer,u_int32_t length)2122 necp_policy_condition_get_type_from_buffer(u_int8_t *buffer, u_int32_t length)
2123 {
2124 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2125 }
2126
2127 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * buffer,u_int32_t length)2128 necp_policy_condition_get_flags_from_buffer(u_int8_t *buffer, u_int32_t length)
2129 {
2130 return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2131 }
2132
2133 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * buffer,u_int32_t length)2134 necp_policy_condition_get_value_length_from_buffer(u_int8_t *buffer, u_int32_t length)
2135 {
2136 return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2137 }
2138
2139 static inline u_int8_t *
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * buffer,u_int32_t length)2140 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t *buffer, u_int32_t length)
2141 {
2142 return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2143 }
2144
2145 static inline bool
necp_policy_condition_is_default(u_int8_t * buffer,u_int32_t length)2146 necp_policy_condition_is_default(u_int8_t *buffer, u_int32_t length)
2147 {
2148 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2149 }
2150
2151 static inline bool
necp_policy_condition_is_application(u_int8_t * buffer,u_int32_t length)2152 necp_policy_condition_is_application(u_int8_t *buffer, u_int32_t length)
2153 {
2154 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2155 }
2156
2157 static inline bool
necp_policy_condition_is_real_application(u_int8_t * buffer,u_int32_t length)2158 necp_policy_condition_is_real_application(u_int8_t *buffer, u_int32_t length)
2159 {
2160 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2161 }
2162
2163 static inline bool
necp_policy_condition_requires_application(u_int8_t * buffer,u_int32_t length)2164 necp_policy_condition_requires_application(u_int8_t *buffer, u_int32_t length)
2165 {
2166 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2167 return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2168 }
2169
2170 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * buffer,u_int32_t length)2171 necp_policy_condition_is_kernel_pid(u_int8_t *buffer, u_int32_t length)
2172 {
2173 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2174 u_int32_t condition_length = 0;
2175 pid_t *condition_value = NULL;
2176
2177 if (type == NECP_POLICY_CONDITION_PID) {
2178 condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2179 if (condition_length >= sizeof(pid_t)) {
2180 condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2181 return *condition_value == 0;
2182 }
2183 }
2184 return false;
2185 }
2186
2187 static bool
necp_policy_condition_is_valid(u_int8_t * buffer,u_int32_t length,u_int8_t policy_result_type)2188 necp_policy_condition_is_valid(u_int8_t *buffer, u_int32_t length, u_int8_t policy_result_type)
2189 {
2190 bool validated = FALSE;
2191 bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2192 policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2193 policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2194 policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2195 policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2196 policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2197 policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2198 policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2199 policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2200 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2201 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2202 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2203 u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2204 switch (type) {
2205 case NECP_POLICY_CONDITION_APPLICATION:
2206 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2207 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2208 condition_length >= sizeof(uuid_t) &&
2209 condition_value != NULL &&
2210 !uuid_is_null(condition_value)) {
2211 validated = TRUE;
2212 }
2213 break;
2214 }
2215 case NECP_POLICY_CONDITION_DOMAIN:
2216 case NECP_POLICY_CONDITION_ACCOUNT:
2217 case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2218 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
2219 if (condition_length > 0) {
2220 validated = TRUE;
2221 }
2222 break;
2223 }
2224 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2225 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2226 validated = TRUE;
2227 }
2228 break;
2229 }
2230 case NECP_POLICY_CONDITION_DEFAULT:
2231 case NECP_POLICY_CONDITION_ALL_INTERFACES:
2232 case NECP_POLICY_CONDITION_ENTITLEMENT:
2233 case NECP_POLICY_CONDITION_PLATFORM_BINARY:
2234 case NECP_POLICY_CONDITION_HAS_CLIENT:
2235 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT:
2236 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2237 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2238 validated = TRUE;
2239 }
2240 break;
2241 }
2242 case NECP_POLICY_CONDITION_SDK_VERSION: {
2243 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2244 condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2245 validated = TRUE;
2246 }
2247 break;
2248 }
2249 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2250 if (condition_length >= sizeof(u_int16_t)) {
2251 validated = TRUE;
2252 }
2253 break;
2254 }
2255 case NECP_POLICY_CONDITION_PID: {
2256 if (condition_length >= sizeof(pid_t) &&
2257 condition_value != NULL) {
2258 validated = TRUE;
2259 }
2260 break;
2261 }
2262 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2263 if (condition_length >= sizeof(u_int32_t)) {
2264 validated = TRUE;
2265 }
2266 break;
2267 }
2268 case NECP_POLICY_CONDITION_UID: {
2269 if (condition_length >= sizeof(uid_t)) {
2270 validated = TRUE;
2271 }
2272 break;
2273 }
2274 case NECP_POLICY_CONDITION_LOCAL_ADDR:
2275 case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2276 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2277 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2278 validated = TRUE;
2279 }
2280 break;
2281 }
2282 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2283 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2284 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2285 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2286 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2287 validated = TRUE;
2288 }
2289 break;
2290 }
2291 case NECP_POLICY_CONDITION_AGENT_TYPE: {
2292 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2293 condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2294 validated = TRUE;
2295 }
2296 break;
2297 }
2298 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2299 if (condition_length >= sizeof(u_int16_t)) {
2300 validated = TRUE;
2301 }
2302 break;
2303 }
2304 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2305 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2306 if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2307 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2308 validated = TRUE;
2309 }
2310 break;
2311 }
2312 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2313 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2314 if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2315 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2316 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2317 validated = TRUE;
2318 }
2319 break;
2320 }
2321 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2322 if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2323 validated = TRUE;
2324 }
2325 break;
2326 }
2327 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2328 validated = TRUE;
2329 break;
2330 }
2331 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2332 validated = TRUE;
2333 break;
2334 }
2335 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2336 if (condition_length >= sizeof(u_int16_t)) {
2337 u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2338 if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2339 validated = TRUE;
2340 }
2341 }
2342 break;
2343 }
2344 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2345 validated = TRUE;
2346 break;
2347 }
2348 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2349 validated = TRUE;
2350 break;
2351 }
2352 case NECP_POLICY_CONDITION_SCHEME_PORT: {
2353 if (condition_length >= sizeof(u_int16_t)) {
2354 validated = TRUE;
2355 }
2356 break;
2357 }
2358 default: {
2359 validated = FALSE;
2360 break;
2361 }
2362 }
2363
2364 if (necp_debug) {
2365 NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2366 }
2367
2368 return validated;
2369 }
2370
2371 static bool
necp_policy_route_rule_is_default(u_int8_t * buffer,u_int32_t length)2372 necp_policy_route_rule_is_default(u_int8_t *buffer, u_int32_t length)
2373 {
2374 return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2375 necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2376 }
2377
2378 static bool
necp_policy_route_rule_is_valid(u_int8_t * buffer,u_int32_t length)2379 necp_policy_route_rule_is_valid(u_int8_t *buffer, u_int32_t length)
2380 {
2381 bool validated = FALSE;
2382 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2383 switch (type) {
2384 case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2385 validated = TRUE;
2386 break;
2387 }
2388 case NECP_ROUTE_RULE_DENY_INTERFACE: {
2389 validated = TRUE;
2390 break;
2391 }
2392 case NECP_ROUTE_RULE_QOS_MARKING: {
2393 validated = TRUE;
2394 break;
2395 }
2396 case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2397 validated = TRUE;
2398 break;
2399 }
2400 case NECP_ROUTE_RULE_USE_NETAGENT:
2401 case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2402 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2403 validated = (rule_length >= sizeof(uuid_t));
2404 break;
2405 }
2406 case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2407 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2408 validated = (rule_length >= sizeof(uint32_t));
2409 break;
2410 }
2411 default: {
2412 validated = FALSE;
2413 break;
2414 }
2415 }
2416
2417 if (necp_debug) {
2418 NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2419 }
2420
2421 return validated;
2422 }
2423
2424 static int
necp_get_posix_error_for_necp_error(int response_error)2425 necp_get_posix_error_for_necp_error(int response_error)
2426 {
2427 switch (response_error) {
2428 case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2429 case NECP_ERROR_INVALID_TLV:
2430 case NECP_ERROR_POLICY_RESULT_INVALID:
2431 case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2432 case NECP_ERROR_ROUTE_RULES_INVALID: {
2433 return EINVAL;
2434 }
2435 case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2436 return ENOENT;
2437 }
2438 case NECP_ERROR_INVALID_PROCESS: {
2439 return EPERM;
2440 }
2441 case NECP_ERROR_INTERNAL:
2442 default: {
2443 return ENOMEM;
2444 }
2445 }
2446 }
2447
2448 static necp_policy_id
necp_handle_policy_add(struct necp_session * session,u_int8_t * tlv_buffer,size_t tlv_buffer_length,int offset,int * return_error)2449 necp_handle_policy_add(struct necp_session *session,
2450 u_int8_t *tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
2451 {
2452 bool has_default_condition = FALSE;
2453 bool has_non_default_condition = FALSE;
2454 bool has_application_condition = FALSE;
2455 bool has_real_application_condition = FALSE;
2456 bool requires_application_condition = FALSE;
2457 bool has_kernel_pid = FALSE;
2458 bool is_pass_skip = FALSE;
2459 u_int8_t *conditions_array = NULL;
2460 u_int32_t conditions_array_size = 0;
2461 int conditions_array_cursor;
2462
2463 bool has_default_route_rule = FALSE;
2464 u_int8_t *route_rules_array = NULL;
2465 u_int32_t route_rules_array_size = 0;
2466 int route_rules_array_cursor;
2467
2468 int cursor;
2469 int error = 0;
2470 u_int32_t response_error = NECP_ERROR_INTERNAL;
2471
2472 necp_policy_order order = 0;
2473 struct necp_session_policy *policy = NULL;
2474 u_int8_t *policy_result = NULL;
2475 u_int32_t policy_result_size = 0;
2476
2477 // Read policy order
2478 error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
2479 if (error) {
2480 NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
2481 response_error = NECP_ERROR_INVALID_TLV;
2482 goto fail;
2483 }
2484
2485 // Read policy result
2486 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
2487 if (error || cursor < 0) {
2488 NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
2489 response_error = NECP_ERROR_INVALID_TLV;
2490 goto fail;
2491 }
2492 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
2493 if (error || policy_result_size == 0) {
2494 NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
2495 response_error = NECP_ERROR_INVALID_TLV;
2496 goto fail;
2497 }
2498 if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
2499 NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
2500 response_error = NECP_ERROR_INVALID_TLV;
2501 goto fail;
2502 }
2503 policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
2504 if (policy_result == NULL) {
2505 NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
2506 response_error = NECP_ERROR_INTERNAL;
2507 goto fail;
2508 }
2509 error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
2510 if (error) {
2511 NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
2512 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2513 goto fail;
2514 }
2515 if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
2516 NECPLOG0(LOG_ERR, "Failed to validate policy result");
2517 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2518 goto fail;
2519 }
2520
2521 if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
2522 // Read route rules conditions
2523 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
2524 cursor >= 0;
2525 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
2526 u_int32_t route_rule_size = 0;
2527 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
2528 if (os_add_overflow(route_rules_array_size,
2529 (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
2530 &route_rules_array_size)) {
2531 NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
2532 response_error = NECP_ERROR_INVALID_TLV;
2533 goto fail;
2534 }
2535 }
2536
2537 if (route_rules_array_size == 0) {
2538 NECPLOG0(LOG_ERR, "Failed to get policy route rules");
2539 response_error = NECP_ERROR_INVALID_TLV;
2540 goto fail;
2541 }
2542 if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
2543 NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
2544 response_error = NECP_ERROR_INVALID_TLV;
2545 goto fail;
2546 }
2547 route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
2548 if (route_rules_array == NULL) {
2549 NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
2550 response_error = NECP_ERROR_INTERNAL;
2551 goto fail;
2552 }
2553
2554 route_rules_array_cursor = 0;
2555 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
2556 cursor >= 0;
2557 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
2558 u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
2559 u_int32_t route_rule_size = 0;
2560 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
2561 if (route_rule_size > 0 &&
2562 (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
2563 // Add type
2564 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
2565 route_rules_array_cursor += sizeof(route_rule_type);
2566
2567 // Add length
2568 memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
2569 route_rules_array_cursor += sizeof(route_rule_size);
2570
2571 // Add value
2572 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
2573
2574 if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
2575 NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
2576 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2577 goto fail;
2578 }
2579
2580 if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
2581 if (has_default_route_rule) {
2582 NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
2583 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2584 goto fail;
2585 }
2586 has_default_route_rule = TRUE;
2587 }
2588
2589 route_rules_array_cursor += route_rule_size;
2590 }
2591 }
2592 }
2593
2594 // Read policy conditions
2595 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
2596 cursor >= 0;
2597 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
2598 u_int32_t condition_size = 0;
2599 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
2600
2601 if (condition_size > 0) {
2602 if (os_add_overflow(conditions_array_size,
2603 (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
2604 &conditions_array_size)) {
2605 NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
2606 response_error = NECP_ERROR_INVALID_TLV;
2607 goto fail;
2608 }
2609 }
2610 }
2611
2612 if (conditions_array_size == 0) {
2613 NECPLOG0(LOG_ERR, "Failed to get policy conditions");
2614 response_error = NECP_ERROR_INVALID_TLV;
2615 goto fail;
2616 }
2617 if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
2618 NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
2619 response_error = NECP_ERROR_INVALID_TLV;
2620 goto fail;
2621 }
2622 conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
2623 if (conditions_array == NULL) {
2624 NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
2625 response_error = NECP_ERROR_INTERNAL;
2626 goto fail;
2627 }
2628
2629 conditions_array_cursor = 0;
2630 for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
2631 cursor >= 0;
2632 cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
2633 u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
2634 u_int32_t condition_size = 0;
2635 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
2636 if (condition_size > 0 &&
2637 (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
2638 // Add type
2639 memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
2640 conditions_array_cursor += sizeof(condition_type);
2641
2642 // Add length
2643 memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
2644 conditions_array_cursor += sizeof(condition_size);
2645
2646 // Add value
2647 necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
2648 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))) {
2649 NECPLOG0(LOG_ERR, "Failed to validate policy condition");
2650 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2651 goto fail;
2652 }
2653
2654 if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
2655 has_default_condition = TRUE;
2656 } else {
2657 has_non_default_condition = TRUE;
2658 }
2659 if (has_default_condition && has_non_default_condition) {
2660 NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
2661 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2662 goto fail;
2663 }
2664
2665 if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
2666 has_application_condition = TRUE;
2667 }
2668
2669 if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
2670 has_real_application_condition = TRUE;
2671 }
2672
2673 if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
2674 requires_application_condition = TRUE;
2675 }
2676
2677 if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
2678 has_kernel_pid = TRUE;
2679 }
2680
2681 conditions_array_cursor += condition_size;
2682 }
2683 }
2684
2685 if (requires_application_condition && !has_application_condition) {
2686 NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
2687 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2688 goto fail;
2689 }
2690
2691 if (has_kernel_pid && !is_pass_skip) {
2692 NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
2693 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2694 goto fail;
2695 }
2696
2697 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) {
2698 response_error = NECP_ERROR_INTERNAL;
2699 goto fail;
2700 }
2701
2702 return policy->local_id;
2703
2704 fail:
2705 if (policy_result != NULL) {
2706 kfree_data(policy_result, policy_result_size);
2707 }
2708 if (conditions_array != NULL) {
2709 kfree_data(conditions_array, conditions_array_size);
2710 }
2711 if (route_rules_array != NULL) {
2712 kfree_data(route_rules_array, route_rules_array_size);
2713 }
2714
2715 if (return_error != NULL) {
2716 *return_error = necp_get_posix_error_for_necp_error(response_error);
2717 }
2718 return 0;
2719 }
2720
2721 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)2722 necp_policy_get_new_id(struct necp_session *session)
2723 {
2724 session->last_policy_id++;
2725 if (session->last_policy_id < 1) {
2726 session->last_policy_id = 1;
2727 }
2728
2729 necp_policy_id newid = session->last_policy_id;
2730
2731 if (newid == 0) {
2732 NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
2733 return 0;
2734 }
2735
2736 return newid;
2737 }
2738
2739 /*
2740 * For the policy dump response this is the structure:
2741 *
2742 * <NECP_PACKET_HEADER>
2743 * {
2744 * type : NECP_TLV_POLICY_DUMP
2745 * length : ...
2746 * value :
2747 * {
2748 * {
2749 * type : NECP_TLV_POLICY_ID
2750 * len : ...
2751 * value : ...
2752 * }
2753 * {
2754 * type : NECP_TLV_POLICY_ORDER
2755 * len : ...
2756 * value : ...
2757 * }
2758 * {
2759 * type : NECP_TLV_POLICY_RESULT_STRING
2760 * len : ...
2761 * value : ...
2762 * }
2763 * {
2764 * type : NECP_TLV_POLICY_OWNER
2765 * len : ...
2766 * value : ...
2767 * }
2768 * {
2769 * type : NECP_TLV_POLICY_CONDITION
2770 * len : ...
2771 * value :
2772 * {
2773 * {
2774 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2775 * len : ...
2776 * value : ...
2777 * }
2778 * {
2779 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2780 * len : ...
2781 * value : ...
2782 * }
2783 * ...
2784 * }
2785 * }
2786 * }
2787 * }
2788 * {
2789 * type : NECP_TLV_POLICY_DUMP
2790 * length : ...
2791 * value :
2792 * {
2793 * {
2794 * type : NECP_TLV_POLICY_ID
2795 * len : ...
2796 * value : ...
2797 * }
2798 * {
2799 * type : NECP_TLV_POLICY_ORDER
2800 * len : ...
2801 * value : ...
2802 * }
2803 * {
2804 * type : NECP_TLV_POLICY_RESULT_STRING
2805 * len : ...
2806 * value : ...
2807 * }
2808 * {
2809 * type : NECP_TLV_POLICY_OWNER
2810 * len : ...
2811 * value : ...
2812 * }
2813 * {
2814 * type : NECP_TLV_POLICY_CONDITION
2815 * len : ...
2816 * value :
2817 * {
2818 * {
2819 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2820 * len : ...
2821 * value : ...
2822 * }
2823 * {
2824 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2825 * len : ...
2826 * value : ...
2827 * }
2828 * ...
2829 * }
2830 * }
2831 * }
2832 * }
2833 * ...
2834 */
2835 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)2836 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
2837 {
2838 struct necp_kernel_socket_policy *policy = NULL;
2839 int policy_i;
2840 int policy_count = 0;
2841 u_int8_t **tlv_buffer_pointers = NULL;
2842 u_int32_t *tlv_buffer_lengths = NULL;
2843 u_int32_t total_tlv_len = 0;
2844 u_int8_t *result_buf = NULL;
2845 u_int8_t *result_buf_cursor = result_buf;
2846 char result_string[MAX_RESULT_STRING_LEN];
2847 char proc_name_string[MAXCOMLEN + 1];
2848
2849 int error_code = 0;
2850 bool error_occured = false;
2851 u_int32_t response_error = NECP_ERROR_INTERNAL;
2852
2853 #define REPORT_ERROR(error) error_occured = true; \
2854 response_error = error; \
2855 goto done
2856
2857 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
2858 REPORT_ERROR(error)
2859
2860 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
2861 if (cred_result != 0) {
2862 NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
2863 REPORT_ERROR(NECP_ERROR_INTERNAL);
2864 }
2865
2866 // LOCK
2867 lck_rw_lock_shared(&necp_kernel_policy_lock);
2868
2869 if (necp_debug) {
2870 NECPLOG0(LOG_DEBUG, "Gathering policies");
2871 }
2872
2873 policy_count = necp_kernel_application_policies_count;
2874
2875 tlv_buffer_pointers = kalloc_type(u_int8_t *, policy_count, M_WAITOK | Z_ZERO);
2876 if (tlv_buffer_pointers == NULL) {
2877 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
2878 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
2879 }
2880
2881 tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
2882 if (tlv_buffer_lengths == NULL) {
2883 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
2884 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
2885 }
2886
2887 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
2888 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
2889
2890 memset(result_string, 0, MAX_RESULT_STRING_LEN);
2891 memset(proc_name_string, 0, MAXCOMLEN + 1);
2892
2893 necp_get_result_description(result_string, policy->result, policy->result_parameter);
2894 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
2895
2896 u_int16_t proc_name_len = strlen(proc_name_string) + 1;
2897 u_int16_t result_string_len = strlen(result_string) + 1;
2898
2899 if (necp_debug) {
2900 NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
2901 }
2902
2903 u_int32_t total_allocated_bytes = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) + // NECP_TLV_POLICY_ID
2904 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) + // NECP_TLV_POLICY_ORDER
2905 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) + // NECP_TLV_POLICY_SESSION_ORDER
2906 sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len + // NECP_TLV_POLICY_RESULT_STRING
2907 sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len + // NECP_TLV_POLICY_OWNER
2908 sizeof(u_int8_t) + sizeof(u_int32_t); // NECP_TLV_POLICY_CONDITION
2909
2910 // We now traverse the condition_mask to see how much space we need to allocate
2911 u_int64_t condition_mask = policy->condition_mask;
2912 u_int8_t num_conditions = 0;
2913 struct necp_string_id_mapping *account_id_entry = NULL;
2914 char if_name[IFXNAMSIZ];
2915 u_int32_t condition_tlv_length = 0;
2916 memset(if_name, 0, sizeof(if_name));
2917
2918 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
2919 num_conditions++;
2920 } else {
2921 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
2922 num_conditions++;
2923 }
2924 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
2925 num_conditions++;
2926 }
2927 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
2928 snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
2929 condition_tlv_length += strlen(if_name) + 1;
2930 num_conditions++;
2931 }
2932 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
2933 condition_tlv_length += sizeof(policy->cond_protocol);
2934 num_conditions++;
2935 }
2936 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
2937 condition_tlv_length += sizeof(uuid_t);
2938 num_conditions++;
2939 }
2940 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
2941 condition_tlv_length += sizeof(uuid_t);
2942 num_conditions++;
2943 }
2944 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
2945 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
2946 u_int32_t domain_len = strlen(policy->cond_domain) + 1;
2947 condition_tlv_length += domain_len;
2948 num_conditions++;
2949 }
2950 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
2951 condition_tlv_length += sizeof(u_int32_t);
2952 num_conditions++;
2953 }
2954 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
2955 account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
2956 u_int32_t account_id_len = 0;
2957 if (account_id_entry) {
2958 account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
2959 }
2960 condition_tlv_length += account_id_len;
2961 num_conditions++;
2962 }
2963 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
2964 condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
2965 num_conditions++;
2966 }
2967 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
2968 condition_tlv_length += sizeof(uid_t);
2969 num_conditions++;
2970 }
2971 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
2972 condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
2973 num_conditions++;
2974 }
2975 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
2976 num_conditions++;
2977 }
2978 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
2979 u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
2980 condition_tlv_length += entitlement_len;
2981 num_conditions++;
2982 }
2983 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
2984 num_conditions++;
2985 }
2986 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
2987 num_conditions++;
2988 }
2989 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
2990 condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
2991 num_conditions++;
2992 }
2993 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
2994 num_conditions++;
2995 }
2996 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
2997 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
2998 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
2999 } else {
3000 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3001 }
3002 num_conditions++;
3003 }
3004 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3005 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3006 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3007 } else {
3008 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3009 }
3010 num_conditions++;
3011 }
3012 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3013 condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3014 num_conditions++;
3015 }
3016 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3017 condition_tlv_length += sizeof(u_int32_t);
3018 num_conditions++;
3019 }
3020 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3021 num_conditions++;
3022 }
3023 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3024 num_conditions++;
3025 }
3026 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3027 u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3028 condition_tlv_length += identifier_len;
3029 num_conditions++;
3030 }
3031 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3032 condition_tlv_length += sizeof(u_int16_t);
3033 num_conditions++;
3034 }
3035 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3036 num_conditions++;
3037 }
3038 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3039 num_conditions++;
3040 }
3041 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3042 condition_tlv_length += sizeof(u_int16_t);
3043 num_conditions++;
3044 }
3045 }
3046
3047 condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t)); // These are for the condition TLVs. The space for "value" is already accounted for above.
3048 total_allocated_bytes += condition_tlv_length;
3049
3050 u_int8_t *tlv_buffer;
3051 tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3052 if (tlv_buffer == NULL) {
3053 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3054 continue;
3055 }
3056
3057 u_int8_t *cursor = tlv_buffer;
3058 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3059 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3060 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3061 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3062 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3063
3064 #define N_QUICK 256
3065 u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3066
3067 u_int8_t *cond_buf; // To be used for condition TLVs
3068 if (condition_tlv_length <= N_QUICK) {
3069 cond_buf = q_cond_buf;
3070 } else {
3071 cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3072 if (cond_buf == NULL) {
3073 NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3074 kfree_data(tlv_buffer, total_allocated_bytes);
3075 continue;
3076 }
3077 }
3078
3079 memset(cond_buf, 0, condition_tlv_length);
3080 u_int8_t *cond_buf_cursor = cond_buf;
3081 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3082 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, 0, "", cond_buf, condition_tlv_length);
3083 } else {
3084 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3085 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_ALL_INTERFACES, 0, "", cond_buf, condition_tlv_length);
3086 }
3087 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3088 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_HAS_CLIENT, 0, "", cond_buf, condition_tlv_length);
3089 }
3090 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3091 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_NETWORKS, 0, "", cond_buf, condition_tlv_length);
3092 }
3093 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3094 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE, strlen(if_name) + 1,
3095 if_name, cond_buf, condition_tlv_length);
3096 }
3097 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3098 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_IP_PROTOCOL, sizeof(policy->cond_protocol), &policy->cond_protocol,
3099 cond_buf, condition_tlv_length);
3100 }
3101 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3102 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3103 if (entry != NULL) {
3104 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, sizeof(entry->uuid), entry->uuid,
3105 cond_buf, condition_tlv_length);
3106 }
3107 }
3108 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3109 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3110 if (entry != NULL) {
3111 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, sizeof(entry->uuid), entry->uuid,
3112 cond_buf, condition_tlv_length);
3113 }
3114 }
3115 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3116 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3117 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN, strlen(policy->cond_domain) + 1, policy->cond_domain,
3118 cond_buf, condition_tlv_length);
3119 }
3120 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3121 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN_FILTER, sizeof(policy->cond_domain_filter), &policy->cond_domain_filter,
3122 cond_buf, condition_tlv_length);
3123 }
3124 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3125 if (account_id_entry != NULL) {
3126 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_ACCOUNT, strlen(account_id_entry->string) + 1, account_id_entry->string,
3127 cond_buf, condition_tlv_length);
3128 }
3129 }
3130 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3131 uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3132 memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3133 memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3134 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_PID, sizeof(pid_buffer), &pid_buffer,
3135 cond_buf, condition_tlv_length);
3136 }
3137 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3138 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_UID, sizeof(policy->cond_uid), &policy->cond_uid,
3139 cond_buf, condition_tlv_length);
3140 }
3141 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3142 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_TRAFFIC_CLASS, sizeof(policy->cond_traffic_class), &policy->cond_traffic_class,
3143 cond_buf, condition_tlv_length);
3144 }
3145 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3146 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, 0, "",
3147 cond_buf, condition_tlv_length);
3148 }
3149 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3150 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, strlen(policy->cond_custom_entitlement) + 1, policy->cond_custom_entitlement,
3151 cond_buf, condition_tlv_length);
3152 }
3153 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3154 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_PLATFORM_BINARY, 0, "", cond_buf, condition_tlv_length);
3155 }
3156 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3157 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT, 0, "", cond_buf, condition_tlv_length);
3158 }
3159 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3160 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION,
3161 sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3162 cond_buf, condition_tlv_length);
3163 }
3164 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3165 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3166 struct necp_policy_condition_addr_range range;
3167 memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3168 memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3169 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, sizeof(range), &range,
3170 cond_buf, condition_tlv_length);
3171 } else {
3172 struct necp_policy_condition_addr addr;
3173 addr.prefix = policy->cond_local_prefix;
3174 memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3175 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, sizeof(addr), &addr,
3176 cond_buf, condition_tlv_length);
3177 }
3178 }
3179 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3180 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3181 struct necp_policy_condition_addr_range range;
3182 memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3183 memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3184 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, sizeof(range), &range,
3185 cond_buf, condition_tlv_length);
3186 } else {
3187 struct necp_policy_condition_addr addr;
3188 addr.prefix = policy->cond_remote_prefix;
3189 memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3190 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, sizeof(addr), &addr,
3191 cond_buf, condition_tlv_length);
3192 }
3193 }
3194 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3195 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE,
3196 sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3197 cond_buf, condition_tlv_length);
3198 }
3199 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3200 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_CLIENT_FLAGS, sizeof(policy->cond_client_flags), &policy->cond_client_flags, cond_buf, condition_tlv_length);
3201 }
3202 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3203 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY, 0, "", cond_buf, condition_tlv_length);
3204 }
3205 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3206 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY, 0, "", cond_buf, condition_tlv_length);
3207 }
3208 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3209 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_SIGNING_IDENTIFIER, strlen(policy->cond_signing_identifier) + 1, policy->cond_signing_identifier,
3210 cond_buf, condition_tlv_length);
3211 }
3212 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3213 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_PACKET_FILTER_TAGS, sizeof(policy->cond_packet_filter_tags), &policy->cond_packet_filter_tags, cond_buf, condition_tlv_length);
3214 }
3215 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3216 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK, 0, "", cond_buf, condition_tlv_length);
3217 }
3218 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3219 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY, 0, "", cond_buf, condition_tlv_length);
3220 }
3221 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3222 cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_SCHEME_PORT, sizeof(policy->cond_scheme_port), &policy->cond_scheme_port, cond_buf, condition_tlv_length);
3223 }
3224 }
3225
3226 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3227 if (cond_buf != q_cond_buf) {
3228 kfree_data(cond_buf, condition_tlv_length);
3229 }
3230
3231 tlv_buffer_pointers[policy_i] = tlv_buffer;
3232 tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3233
3234 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
3235 total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3236 }
3237
3238 // UNLOCK
3239 lck_rw_done(&necp_kernel_policy_lock);
3240
3241 // Copy out
3242 if (out_buffer != 0) {
3243 if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3244 NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3245 REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3246 }
3247
3248 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3249 result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3250 if (result_buf == NULL) {
3251 NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3252 REPORT_ERROR(NECP_ERROR_INTERNAL);
3253 }
3254
3255 // Add four bytes for total length at the start
3256 memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3257
3258 // Copy the TLVs
3259 result_buf_cursor = result_buf + sizeof(u_int32_t);
3260 for (int i = 0; i < policy_count; i++) {
3261 if (tlv_buffer_pointers[i] != NULL) {
3262 result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3263 result_buf, total_tlv_len + sizeof(u_int32_t));
3264 }
3265 }
3266
3267 int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3268 if (copy_error) {
3269 NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3270 REPORT_ERROR(NECP_ERROR_INTERNAL);
3271 }
3272 }
3273
3274 done:
3275
3276 if (error_occured) {
3277 error_code = necp_get_posix_error_for_necp_error(response_error);
3278 }
3279
3280 if (result_buf != NULL) {
3281 kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3282 }
3283
3284 if (tlv_buffer_pointers != NULL) {
3285 for (int i = 0; i < policy_count; i++) {
3286 if (tlv_buffer_pointers[i] != NULL) {
3287 kfree_data_addr(tlv_buffer_pointers[i]);
3288 tlv_buffer_pointers[i] = NULL;
3289 }
3290 }
3291 kfree_type(u_int8_t *, policy_count, tlv_buffer_pointers);
3292 }
3293
3294 if (tlv_buffer_lengths != NULL) {
3295 kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3296 }
3297 #undef N_QUICK
3298 #undef RESET_COND_BUF
3299 #undef REPORT_ERROR
3300 #undef UNLOCK_AND_REPORT_ERROR
3301
3302 return error_code;
3303 }
3304
3305 static struct necp_session_policy *
necp_policy_create(struct necp_session * session,necp_policy_order order,u_int8_t * conditions_array,u_int32_t conditions_array_size,u_int8_t * route_rules_array,u_int32_t route_rules_array_size,u_int8_t * result,u_int32_t result_size)3306 necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *conditions_array, u_int32_t conditions_array_size, u_int8_t *route_rules_array, u_int32_t route_rules_array_size, u_int8_t *result, u_int32_t result_size)
3307 {
3308 struct necp_session_policy *new_policy = NULL;
3309 struct necp_session_policy *tmp_policy = NULL;
3310
3311 if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3312 goto done;
3313 }
3314
3315 new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3316 new_policy->applied = FALSE;
3317 new_policy->pending_deletion = FALSE;
3318 new_policy->pending_update = FALSE;
3319 new_policy->order = order;
3320 new_policy->conditions = conditions_array;
3321 new_policy->conditions_size = conditions_array_size;
3322 new_policy->route_rules = route_rules_array;
3323 new_policy->route_rules_size = route_rules_array_size;
3324 new_policy->result = result;
3325 new_policy->result_size = result_size;
3326 new_policy->local_id = necp_policy_get_new_id(session);
3327
3328 LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3329
3330 session->dirty = TRUE;
3331
3332 if (necp_debug) {
3333 NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3334 }
3335 done:
3336 return new_policy;
3337 }
3338
3339 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3340 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3341 {
3342 struct necp_session_policy *policy = NULL;
3343 if (policy_id == 0) {
3344 return NULL;
3345 }
3346
3347 LIST_FOREACH(policy, &session->policies, chain) {
3348 if (policy->local_id == policy_id) {
3349 return policy;
3350 }
3351 }
3352
3353 return NULL;
3354 }
3355
3356 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3357 necp_policy_get_result_type(struct necp_session_policy *policy)
3358 {
3359 return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3360 }
3361
3362 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3363 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3364 {
3365 return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3366 }
3367
3368 static bool
necp_policy_get_result_parameter(struct necp_session_policy * policy,u_int8_t * parameter_buffer,u_int32_t parameter_buffer_length)3369 necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t *parameter_buffer, u_int32_t parameter_buffer_length)
3370 {
3371 if (policy) {
3372 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3373 if (parameter_buffer_length >= parameter_length) {
3374 u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3375 if (parameter && parameter_buffer) {
3376 memcpy(parameter_buffer, parameter, parameter_length);
3377 return TRUE;
3378 }
3379 }
3380 }
3381
3382 return FALSE;
3383 }
3384
3385 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)3386 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
3387 {
3388 if (session == NULL || policy == NULL) {
3389 return FALSE;
3390 }
3391
3392 policy->pending_deletion = TRUE;
3393 session->dirty = TRUE;
3394
3395 if (necp_debug) {
3396 NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
3397 }
3398 return TRUE;
3399 }
3400
3401 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)3402 necp_policy_mark_all_for_deletion(struct necp_session *session)
3403 {
3404 struct necp_session_policy *policy = NULL;
3405 struct necp_session_policy *temp_policy = NULL;
3406
3407 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
3408 necp_policy_mark_for_deletion(session, policy);
3409 }
3410
3411 return TRUE;
3412 }
3413
3414 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)3415 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
3416 {
3417 if (session == NULL || policy == NULL) {
3418 return FALSE;
3419 }
3420
3421 LIST_REMOVE(policy, chain);
3422
3423 if (policy->result) {
3424 kfree_data(policy->result, policy->result_size);
3425 policy->result = NULL;
3426 }
3427
3428 if (policy->conditions) {
3429 kfree_data(policy->conditions, policy->conditions_size);
3430 policy->conditions = NULL;
3431 }
3432
3433 if (policy->route_rules) {
3434 kfree_data(policy->route_rules, policy->route_rules_size);
3435 policy->route_rules = NULL;
3436 }
3437
3438 zfree(necp_session_policy_zone, policy);
3439
3440 if (necp_debug) {
3441 NECPLOG0(LOG_DEBUG, "Removed NECP policy");
3442 }
3443 return TRUE;
3444 }
3445
3446 static bool
necp_policy_unapply(struct necp_session_policy * policy)3447 necp_policy_unapply(struct necp_session_policy *policy)
3448 {
3449 int i = 0;
3450 if (policy == NULL) {
3451 return FALSE;
3452 }
3453
3454 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3455
3456 // Release local uuid mappings
3457 if (!uuid_is_null(policy->applied_app_uuid)) {
3458 bool removed_mapping = FALSE;
3459 if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
3460 necp_uuid_app_id_mappings_dirty = TRUE;
3461 necp_num_uuid_app_id_mappings--;
3462 }
3463 uuid_clear(policy->applied_app_uuid);
3464 }
3465 if (!uuid_is_null(policy->applied_real_app_uuid)) {
3466 necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
3467 uuid_clear(policy->applied_real_app_uuid);
3468 }
3469 if (!uuid_is_null(policy->applied_result_uuid)) {
3470 necp_remove_uuid_service_id_mapping(policy->applied_result_uuid);
3471 uuid_clear(policy->applied_result_uuid);
3472 }
3473
3474 // Release string mappings
3475 if (policy->applied_account != NULL) {
3476 necp_remove_string_to_id_mapping(&necp_account_id_list, policy->applied_account);
3477 kfree_data(policy->applied_account, policy->applied_account_size);
3478 policy->applied_account = NULL;
3479 }
3480
3481 // Release route rule
3482 if (policy->applied_route_rules_id != 0) {
3483 necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
3484 policy->applied_route_rules_id = 0;
3485 }
3486
3487 // Remove socket policies
3488 for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
3489 if (policy->kernel_socket_policies[i] != 0) {
3490 necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
3491 policy->kernel_socket_policies[i] = 0;
3492 }
3493 }
3494
3495 // Remove IP output policies
3496 for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
3497 if (policy->kernel_ip_output_policies[i] != 0) {
3498 necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
3499 policy->kernel_ip_output_policies[i] = 0;
3500 }
3501 }
3502
3503 policy->applied = FALSE;
3504
3505 return TRUE;
3506 }
3507
3508 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
3509 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
3510 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
3511 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
3512 struct necp_policy_result_ip_tunnel {
3513 u_int32_t secondary_result;
3514 char interface_name[IFXNAMSIZ];
3515 } __attribute__((__packed__));
3516
3517 struct necp_policy_result_service {
3518 uuid_t identifier;
3519 u_int32_t data;
3520 } __attribute__((__packed__));
3521
3522 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy)3523 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
3524 {
3525 bool socket_only_conditions = FALSE;
3526 bool socket_ip_conditions = FALSE;
3527
3528 bool socket_layer_non_id_conditions = FALSE;
3529 bool ip_output_layer_non_id_conditions = FALSE;
3530 bool ip_output_layer_non_id_only = FALSE;
3531 bool ip_output_layer_id_condition = FALSE;
3532 bool ip_output_layer_tunnel_condition_from_id = FALSE;
3533 bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
3534 necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
3535
3536 u_int64_t master_condition_mask = 0;
3537 u_int64_t master_condition_negated_mask = 0;
3538 ifnet_t cond_bound_interface = NULL;
3539 u_int32_t cond_account_id = 0;
3540 char *cond_domain = NULL;
3541 u_int32_t cond_domain_filter = 0;
3542 char *cond_custom_entitlement = NULL;
3543 char *cond_signing_identifier = NULL;
3544 pid_t cond_pid = 0;
3545 int32_t cond_pid_version = 0;
3546 uid_t cond_uid = 0;
3547 necp_app_id cond_app_id = 0;
3548 necp_app_id cond_real_app_id = 0;
3549 struct necp_policy_condition_tc_range cond_traffic_class;
3550 cond_traffic_class.start_tc = 0;
3551 cond_traffic_class.end_tc = 0;
3552 u_int16_t cond_protocol = 0;
3553 union necp_sockaddr_union cond_local_start;
3554 union necp_sockaddr_union cond_local_end;
3555 u_int8_t cond_local_prefix = 0;
3556 union necp_sockaddr_union cond_remote_start;
3557 union necp_sockaddr_union cond_remote_end;
3558 u_int8_t cond_remote_prefix = 0;
3559 u_int32_t cond_client_flags = 0;
3560 u_int32_t offset = 0;
3561 u_int8_t ultimate_result = 0;
3562 u_int32_t secondary_result = 0;
3563 struct necp_policy_condition_agent_type cond_agent_type = {};
3564 struct necp_policy_condition_sdk_version cond_sdk_version = {};
3565 u_int16_t cond_packet_filter_tags = 0;
3566 u_int16_t cond_scheme_port = 0;
3567 necp_kernel_policy_result_parameter secondary_result_parameter;
3568 memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
3569 u_int32_t cond_last_interface_index = 0;
3570 necp_kernel_policy_result_parameter ultimate_result_parameter;
3571 memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
3572
3573 if (policy == NULL) {
3574 return FALSE;
3575 }
3576
3577 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3578
3579 // Process conditions
3580 while (offset < policy->conditions_size) {
3581 u_int32_t length = 0;
3582 u_int8_t *value = necp_buffer_get_tlv_value(policy->conditions, offset, &length);
3583
3584 u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
3585 u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
3586 bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
3587 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
3588 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
3589 switch (condition_type) {
3590 case NECP_POLICY_CONDITION_DEFAULT: {
3591 socket_ip_conditions = TRUE;
3592 break;
3593 }
3594 case NECP_POLICY_CONDITION_ALL_INTERFACES: {
3595 master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
3596 socket_ip_conditions = TRUE;
3597 break;
3598 }
3599 case NECP_POLICY_CONDITION_HAS_CLIENT: {
3600 master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
3601 socket_only_conditions = TRUE;
3602 break;
3603 }
3604 case NECP_POLICY_CONDITION_ENTITLEMENT: {
3605 if (condition_length > 0) {
3606 if (cond_custom_entitlement == NULL) {
3607 cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
3608 if (cond_custom_entitlement != NULL) {
3609 master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
3610 socket_only_conditions = TRUE;
3611 }
3612 }
3613 } else {
3614 master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
3615 socket_only_conditions = TRUE;
3616 }
3617 break;
3618 }
3619 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
3620 master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
3621 socket_only_conditions = TRUE;
3622 break;
3623 }
3624 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
3625 master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
3626 socket_only_conditions = TRUE;
3627 break;
3628 }
3629 case NECP_POLICY_CONDITION_SDK_VERSION: {
3630 if (condition_length >= sizeof(cond_sdk_version)) {
3631 master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
3632 memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
3633 socket_only_conditions = TRUE;
3634 }
3635 break;
3636 }
3637 case NECP_POLICY_CONDITION_DOMAIN: {
3638 // Make sure there is only one such rule
3639 if (condition_length > 0 && cond_domain == NULL) {
3640 const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
3641
3642 u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
3643 cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
3644 if (cond_domain != NULL) {
3645 master_condition_mask |= mask_value;
3646 if (condition_is_negative) {
3647 master_condition_negated_mask |= mask_value;
3648 }
3649 socket_only_conditions = TRUE;
3650 }
3651 }
3652 break;
3653 }
3654 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
3655 // Make sure there is only one such rule
3656 if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
3657 memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
3658 if (cond_domain_filter != 0) {
3659 master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
3660 if (condition_is_negative) {
3661 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
3662 }
3663 socket_only_conditions = TRUE;
3664 }
3665 }
3666 break;
3667 }
3668 case NECP_POLICY_CONDITION_ACCOUNT: {
3669 // Make sure there is only one such rule
3670 if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
3671 char *string = NULL;
3672 string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
3673 if (string != NULL) {
3674 memcpy(string, condition_value, condition_length);
3675 string[condition_length] = 0;
3676 cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, string);
3677 if (cond_account_id != 0) {
3678 policy->applied_account = string; // Save the string in parent policy
3679 policy->applied_account_size = condition_length + 1;
3680 master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
3681 if (condition_is_negative) {
3682 master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
3683 }
3684 socket_only_conditions = TRUE;
3685 } else {
3686 kfree_data(string, condition_length + 1);
3687 }
3688 }
3689 }
3690 break;
3691 }
3692 case NECP_POLICY_CONDITION_APPLICATION: {
3693 // Make sure there is only one such rule, because we save the uuid in the policy
3694 if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
3695 bool allocated_mapping = FALSE;
3696 uuid_t application_uuid;
3697 memcpy(application_uuid, condition_value, sizeof(uuid_t));
3698 cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
3699 if (cond_app_id != 0) {
3700 if (allocated_mapping) {
3701 necp_uuid_app_id_mappings_dirty = TRUE;
3702 necp_num_uuid_app_id_mappings++;
3703 }
3704 uuid_copy(policy->applied_app_uuid, application_uuid);
3705 master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
3706 if (condition_is_negative) {
3707 master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
3708 }
3709 socket_only_conditions = TRUE;
3710 }
3711 }
3712 break;
3713 }
3714 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
3715 // Make sure there is only one such rule, because we save the uuid in the policy
3716 if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
3717 uuid_t real_application_uuid;
3718 memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
3719 cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
3720 if (cond_real_app_id != 0) {
3721 uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
3722 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
3723 if (condition_is_negative) {
3724 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
3725 }
3726 socket_only_conditions = TRUE;
3727 }
3728 }
3729 break;
3730 }
3731 case NECP_POLICY_CONDITION_PID: {
3732 if (condition_length >= sizeof(pid_t)) {
3733 master_condition_mask |= NECP_KERNEL_CONDITION_PID;
3734 if (condition_is_negative) {
3735 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
3736 }
3737 memcpy(&cond_pid, condition_value, sizeof(cond_pid));
3738 if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
3739 memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
3740 }
3741 socket_only_conditions = TRUE;
3742 }
3743 break;
3744 }
3745 case NECP_POLICY_CONDITION_UID: {
3746 if (condition_length >= sizeof(uid_t)) {
3747 master_condition_mask |= NECP_KERNEL_CONDITION_UID;
3748 if (condition_is_negative) {
3749 master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
3750 }
3751 memcpy(&cond_uid, condition_value, sizeof(cond_uid));
3752 socket_only_conditions = TRUE;
3753 }
3754 break;
3755 }
3756 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
3757 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
3758 master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
3759 if (condition_is_negative) {
3760 master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
3761 }
3762 memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
3763 socket_only_conditions = TRUE;
3764 }
3765 break;
3766 }
3767 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
3768 if (condition_length <= IFXNAMSIZ && condition_length > 0) {
3769 char interface_name[IFXNAMSIZ];
3770 memcpy(interface_name, condition_value, condition_length);
3771 interface_name[condition_length - 1] = 0; // Make sure the string is NULL terminated
3772 if (ifnet_find_by_name(interface_name, &cond_bound_interface) == 0) {
3773 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
3774 if (condition_is_negative) {
3775 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
3776 }
3777 }
3778 socket_ip_conditions = TRUE;
3779 }
3780 break;
3781 }
3782 case NECP_POLICY_CONDITION_IP_PROTOCOL:
3783 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
3784 if (condition_length >= sizeof(u_int16_t)) {
3785 master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
3786 if (condition_is_negative) {
3787 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
3788 }
3789 memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
3790 if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
3791 socket_only_conditions = TRUE;
3792 } else {
3793 socket_ip_conditions = TRUE;
3794 }
3795 }
3796 break;
3797 }
3798 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
3799 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
3800 socket_ip_conditions = TRUE;
3801 break;
3802 }
3803 case NECP_POLICY_CONDITION_LOCAL_ADDR:
3804 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
3805 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
3806 if (!necp_address_is_valid(&address_struct->address.sa)) {
3807 break;
3808 }
3809
3810 cond_local_prefix = address_struct->prefix;
3811 memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
3812 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
3813 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
3814 if (condition_is_negative) {
3815 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
3816 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
3817 }
3818 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
3819 socket_only_conditions = TRUE;
3820 } else {
3821 socket_ip_conditions = TRUE;
3822 }
3823 break;
3824 }
3825 case NECP_POLICY_CONDITION_REMOTE_ADDR:
3826 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
3827 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
3828 if (!necp_address_is_valid(&address_struct->address.sa)) {
3829 break;
3830 }
3831
3832 cond_remote_prefix = address_struct->prefix;
3833 memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
3834 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
3835 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
3836 if (condition_is_negative) {
3837 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
3838 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
3839 }
3840 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
3841 socket_only_conditions = TRUE;
3842 } else {
3843 socket_ip_conditions = TRUE;
3844 }
3845 break;
3846 }
3847 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
3848 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
3849 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
3850 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
3851 !necp_address_is_valid(&address_struct->end_address.sa)) {
3852 break;
3853 }
3854
3855 memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
3856 memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
3857 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
3858 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
3859 if (condition_is_negative) {
3860 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
3861 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
3862 }
3863 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
3864 socket_only_conditions = TRUE;
3865 } else {
3866 socket_ip_conditions = TRUE;
3867 }
3868 break;
3869 }
3870 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
3871 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
3872 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
3873 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
3874 !necp_address_is_valid(&address_struct->end_address.sa)) {
3875 break;
3876 }
3877
3878 memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
3879 memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
3880 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
3881 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
3882 if (condition_is_negative) {
3883 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
3884 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
3885 }
3886 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
3887 socket_only_conditions = TRUE;
3888 } else {
3889 socket_ip_conditions = TRUE;
3890 }
3891 break;
3892 }
3893 case NECP_POLICY_CONDITION_AGENT_TYPE: {
3894 if (condition_length >= sizeof(cond_agent_type)) {
3895 master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
3896 memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
3897 socket_only_conditions = TRUE;
3898 }
3899 break;
3900 }
3901 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
3902 if (condition_is_negative) {
3903 master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
3904 }
3905 master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
3906 socket_only_conditions = TRUE;
3907 if (condition_length >= sizeof(u_int32_t)) {
3908 memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
3909 } else {
3910 // Empty means match on fallback traffic
3911 cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
3912 }
3913 break;
3914 }
3915 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
3916 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
3917 if (condition_is_negative) {
3918 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
3919 }
3920 socket_only_conditions = TRUE;
3921 break;
3922 }
3923 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
3924 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
3925 if (condition_is_negative) {
3926 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
3927 }
3928 socket_only_conditions = TRUE;
3929 break;
3930 }
3931 case NECP_POLICY_CONDITION_SCHEME_PORT: {
3932 master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
3933 if (condition_is_negative) {
3934 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
3935 }
3936 memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
3937 socket_ip_conditions = TRUE;
3938 break;
3939 }
3940 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
3941 if (condition_length > 0) {
3942 if (cond_signing_identifier == NULL) {
3943 cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
3944 if (cond_signing_identifier != NULL) {
3945 master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
3946 socket_only_conditions = TRUE;
3947 if (condition_is_negative) {
3948 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
3949 }
3950 }
3951 }
3952 }
3953 break;
3954 }
3955 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
3956 if (condition_length >= sizeof(u_int16_t)) {
3957 master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
3958 if (condition_is_negative) {
3959 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
3960 }
3961 memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
3962 socket_ip_conditions = TRUE;
3963 }
3964 break;
3965 }
3966 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
3967 master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
3968 if (condition_is_negative) {
3969 master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
3970 }
3971 socket_only_conditions = TRUE;
3972 break;
3973 }
3974 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
3975 master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
3976 if (condition_is_negative) {
3977 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
3978 }
3979 socket_only_conditions = TRUE;
3980 break;
3981 }
3982 default: {
3983 break;
3984 }
3985 }
3986
3987 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
3988 }
3989
3990 // Process result
3991 ultimate_result = necp_policy_get_result_type(policy);
3992 switch (ultimate_result) {
3993 case NECP_POLICY_RESULT_PASS: {
3994 u_int32_t pass_flags = 0;
3995 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
3996 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
3997 ultimate_result_parameter.pass_flags = pass_flags;
3998 }
3999 }
4000 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4001 socket_layer_non_id_conditions = TRUE;
4002 ip_output_layer_id_condition = TRUE;
4003 } else if (socket_ip_conditions) {
4004 socket_layer_non_id_conditions = TRUE;
4005 ip_output_layer_id_condition = TRUE;
4006 ip_output_layer_non_id_conditions = TRUE;
4007 }
4008 break;
4009 }
4010 case NECP_POLICY_RESULT_DROP: {
4011 u_int32_t drop_flags = 0;
4012 if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4013 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4014 ultimate_result_parameter.drop_flags = drop_flags;
4015 }
4016 }
4017 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4018 socket_layer_non_id_conditions = TRUE;
4019 } else if (socket_ip_conditions) {
4020 socket_layer_non_id_conditions = TRUE;
4021 ip_output_layer_non_id_conditions = TRUE;
4022 ip_output_layer_non_id_only = TRUE; // Only apply drop to packets that didn't go through socket layer
4023 }
4024 break;
4025 }
4026 case NECP_POLICY_RESULT_SKIP: {
4027 u_int32_t skip_policy_order = 0;
4028 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4029 ultimate_result_parameter.skip_policy_order = skip_policy_order;
4030 }
4031
4032 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4033 socket_layer_non_id_conditions = TRUE;
4034 ip_output_layer_id_condition = TRUE;
4035 } else if (socket_ip_conditions) {
4036 socket_layer_non_id_conditions = TRUE;
4037 ip_output_layer_non_id_conditions = TRUE;
4038 }
4039 break;
4040 }
4041 case NECP_POLICY_RESULT_SOCKET_DIVERT:
4042 case NECP_POLICY_RESULT_SOCKET_FILTER: {
4043 u_int32_t control_unit = 0;
4044 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4045 ultimate_result_parameter.flow_divert_control_unit = control_unit;
4046 }
4047 socket_layer_non_id_conditions = TRUE;
4048 break;
4049 }
4050 case NECP_POLICY_RESULT_IP_TUNNEL: {
4051 struct necp_policy_result_ip_tunnel tunnel_parameters;
4052 u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4053 if (tunnel_parameters_length > sizeof(u_int32_t) &&
4054 tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4055 necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4056 ifnet_t tunnel_interface = NULL;
4057 tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0; // Make sure the string is NULL terminated
4058 if (ifnet_find_by_name(tunnel_parameters.interface_name, &tunnel_interface) == 0) {
4059 ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4060 ifnet_release(tunnel_interface);
4061 }
4062
4063 secondary_result = tunnel_parameters.secondary_result;
4064 if (secondary_result) {
4065 cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4066 }
4067 }
4068
4069 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4070 socket_layer_non_id_conditions = TRUE;
4071 ip_output_layer_id_condition = TRUE;
4072 if (secondary_result) {
4073 ip_output_layer_tunnel_condition_from_id = TRUE;
4074 }
4075 } else if (socket_ip_conditions) {
4076 socket_layer_non_id_conditions = TRUE;
4077 ip_output_layer_id_condition = TRUE;
4078 ip_output_layer_non_id_conditions = TRUE;
4079 if (secondary_result) {
4080 ip_output_layer_tunnel_condition_from_id = TRUE;
4081 ip_output_layer_tunnel_condition_from_non_id = TRUE;
4082 }
4083 }
4084 break;
4085 }
4086 case NECP_POLICY_RESULT_USE_NETAGENT:
4087 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4088 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4089 uuid_t netagent_uuid;
4090 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4091 ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
4092 if (ultimate_result_parameter.netagent_id != 0) {
4093 uuid_copy(policy->applied_result_uuid, netagent_uuid);
4094 socket_layer_non_id_conditions = TRUE;
4095 }
4096 }
4097 break;
4098 }
4099 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4100 u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4101 if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4102 char interface_name[IFXNAMSIZ];
4103 ifnet_t scope_interface = NULL;
4104 necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4105 interface_name[interface_name_length - 1] = 0; // Make sure the string is NULL terminated
4106 if (ifnet_find_by_name(interface_name, &scope_interface) == 0) {
4107 ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4108 socket_layer_non_id_conditions = TRUE;
4109 ifnet_release(scope_interface);
4110 }
4111 }
4112 break;
4113 }
4114 case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4115 socket_layer_non_id_conditions = TRUE;
4116 break;
4117 }
4118 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4119 socket_layer_non_id_conditions = TRUE;
4120 break;
4121 }
4122 case NECP_POLICY_RESULT_ROUTE_RULES: {
4123 if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4124 u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size);
4125 if (route_rule_id > 0) {
4126 policy->applied_route_rules_id = route_rule_id;
4127 ultimate_result_parameter.route_rule_id = route_rule_id;
4128 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4129 socket_layer_non_id_conditions = TRUE;
4130 } else if (socket_ip_conditions) {
4131 socket_layer_non_id_conditions = TRUE;
4132 ip_output_layer_non_id_conditions = TRUE;
4133 ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4134 }
4135 }
4136 }
4137 break;
4138 }
4139 default: {
4140 break;
4141 }
4142 }
4143
4144 if (socket_layer_non_id_conditions) {
4145 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_pid, cond_pid_version, cond_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, ultimate_result, ultimate_result_parameter);
4146
4147 if (policy_id == 0) {
4148 NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4149 goto fail;
4150 }
4151
4152 cond_ip_output_layer_id = policy_id;
4153 policy->kernel_socket_policies[0] = policy_id;
4154 }
4155
4156 if (ip_output_layer_non_id_conditions) {
4157 u_int64_t condition_mask = master_condition_mask;
4158 if (ip_output_layer_non_id_only) {
4159 condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4160 }
4161
4162 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, ultimate_result, ultimate_result_parameter);
4163
4164 if (policy_id == 0) {
4165 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4166 goto fail;
4167 }
4168
4169 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4170 }
4171
4172 if (ip_output_layer_id_condition) {
4173 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, ultimate_result, ultimate_result_parameter);
4174
4175 if (policy_id == 0) {
4176 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4177 goto fail;
4178 }
4179
4180 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4181 }
4182
4183 // Extra policies for IP Output tunnels for when packets loop back
4184 if (ip_output_layer_tunnel_condition_from_id) {
4185 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, secondary_result, secondary_result_parameter);
4186
4187 if (policy_id == 0) {
4188 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4189 goto fail;
4190 }
4191
4192 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4193 }
4194
4195 if (ip_output_layer_tunnel_condition_from_id) {
4196 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, secondary_result, secondary_result_parameter);
4197
4198 if (policy_id == 0) {
4199 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4200 goto fail;
4201 }
4202
4203 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4204 }
4205
4206 policy->applied = TRUE;
4207 policy->pending_update = FALSE;
4208 return TRUE;
4209
4210 fail:
4211 return FALSE;
4212 }
4213
4214 static void
necp_policy_apply_all(struct necp_session * session)4215 necp_policy_apply_all(struct necp_session *session)
4216 {
4217 struct necp_session_policy *policy = NULL;
4218 struct necp_session_policy *temp_policy = NULL;
4219 struct kev_necp_policies_changed_data kev_data;
4220 kev_data.changed_count = 0;
4221
4222 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4223
4224 // Remove exisiting applied policies
4225 if (session->dirty) {
4226 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4227 if (policy->pending_deletion) {
4228 if (policy->applied) {
4229 necp_policy_unapply(policy);
4230 }
4231 // Delete the policy
4232 necp_policy_delete(session, policy);
4233 } else if (!policy->applied) {
4234 necp_policy_apply(session, policy);
4235 } else if (policy->pending_update) {
4236 // Must have been applied, but needs an update. Remove and re-add.
4237 necp_policy_unapply(policy);
4238 necp_policy_apply(session, policy);
4239 }
4240 }
4241
4242 necp_kernel_socket_policies_update_uuid_table();
4243 necp_kernel_socket_policies_reprocess();
4244 necp_kernel_ip_output_policies_reprocess();
4245
4246 // Clear dirty bit flags
4247 session->dirty = FALSE;
4248 }
4249
4250 lck_rw_done(&necp_kernel_policy_lock);
4251
4252 necp_update_all_clients();
4253 necp_post_change_event(&kev_data);
4254
4255 if (necp_debug) {
4256 NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4257 }
4258 }
4259
4260 // Kernel Policy Management
4261 // ---------------------
4262 // Kernel policies are derived from session policies
4263 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4264 necp_kernel_policy_get_new_id(bool socket_level)
4265 {
4266 static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4267 static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4268
4269 necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4270
4271 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4272
4273 if (socket_level) {
4274 bool wrapped = FALSE;
4275 do {
4276 necp_last_kernel_socket_policy_id++;
4277 if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4278 necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4279 if (wrapped) {
4280 // Already wrapped, give up
4281 NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4282 return NECP_KERNEL_POLICY_ID_NONE;
4283 }
4284 necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4285 wrapped = TRUE;
4286 }
4287 newid = necp_last_kernel_socket_policy_id;
4288 } while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4289 } else {
4290 bool wrapped = FALSE;
4291 do {
4292 necp_last_kernel_ip_policy_id++;
4293 if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4294 if (wrapped) {
4295 // Already wrapped, give up
4296 NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4297 return NECP_KERNEL_POLICY_ID_NONE;
4298 }
4299 necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4300 wrapped = TRUE;
4301 }
4302 newid = necp_last_kernel_ip_policy_id;
4303 } while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4304 }
4305
4306 if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4307 NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4308 return NECP_KERNEL_POLICY_ID_NONE;
4309 }
4310
4311 return newid;
4312 }
4313
4314 #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_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)
4315
4316 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,u_int32_t cond_account_id,char * cond_domain,u_int32_t cond_domain_filter,pid_t cond_pid,int32_t cond_pid_version,uid_t cond_uid,ifnet_t cond_bound_interface,struct necp_policy_condition_tc_range cond_traffic_class,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,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,u_int16_t cond_packet_filter_tags,u_int16_t cond_scheme_port,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)4317 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, u_int32_t cond_account_id, char *cond_domain, u_int32_t cond_domain_filter, pid_t cond_pid, int32_t cond_pid_version, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, 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, 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, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
4318 {
4319 struct necp_kernel_socket_policy *new_kernel_policy = NULL;
4320 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4321
4322 new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
4323
4324 new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
4325 new_kernel_policy->order = order;
4326 new_kernel_policy->session_order = session_order;
4327 new_kernel_policy->session_pid = session_pid;
4328
4329 // Sanitize condition mask
4330 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
4331 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
4332 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4333 }
4334 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
4335 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
4336 }
4337 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
4338 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4339 }
4340 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
4341 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4342 }
4343 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
4344 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
4345 }
4346 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
4347 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
4348 }
4349 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
4350
4351 // Set condition values
4352 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4353 new_kernel_policy->cond_app_id = cond_app_id;
4354 }
4355 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4356 new_kernel_policy->cond_real_app_id = cond_real_app_id;
4357 }
4358 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
4359 new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
4360 }
4361 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4362 new_kernel_policy->cond_account_id = cond_account_id;
4363 }
4364 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
4365 (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
4366 new_kernel_policy->cond_domain = cond_domain;
4367 new_kernel_policy->cond_domain_dot_count = necp_count_dots(cond_domain, strlen(cond_domain));
4368 }
4369 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
4370 new_kernel_policy->cond_domain_filter = cond_domain_filter;
4371 }
4372 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
4373 new_kernel_policy->cond_pid = cond_pid;
4374 new_kernel_policy->cond_pid_version = cond_pid_version;
4375 }
4376 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
4377 new_kernel_policy->cond_uid = cond_uid;
4378 }
4379 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
4380 if (cond_bound_interface) {
4381 ifnet_reference(cond_bound_interface);
4382 }
4383 new_kernel_policy->cond_bound_interface = cond_bound_interface;
4384 }
4385 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4386 new_kernel_policy->cond_traffic_class = cond_traffic_class;
4387 }
4388 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4389 new_kernel_policy->cond_protocol = cond_protocol;
4390 }
4391 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4392 memcpy(&new_kernel_policy->cond_local_start, cond_local_start, cond_local_start->sa.sa_len);
4393 }
4394 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4395 memcpy(&new_kernel_policy->cond_local_end, cond_local_end, cond_local_end->sa.sa_len);
4396 }
4397 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4398 new_kernel_policy->cond_local_prefix = cond_local_prefix;
4399 }
4400 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4401 memcpy(&new_kernel_policy->cond_remote_start, cond_remote_start, cond_remote_start->sa.sa_len);
4402 }
4403 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4404 memcpy(&new_kernel_policy->cond_remote_end, cond_remote_end, cond_remote_end->sa.sa_len);
4405 }
4406 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4407 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
4408 }
4409 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
4410 memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
4411 }
4412 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
4413 memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
4414 }
4415 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
4416 new_kernel_policy->cond_client_flags = cond_client_flags;
4417 }
4418 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
4419 new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
4420 }
4421 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
4422 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
4423 }
4424 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
4425 new_kernel_policy->cond_scheme_port = cond_scheme_port;
4426 }
4427
4428 new_kernel_policy->result = result;
4429 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
4430
4431 if (necp_debug) {
4432 NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
4433 }
4434 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
4435
4436 return new_kernel_policy ? new_kernel_policy->id : 0;
4437 }
4438
4439 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)4440 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
4441 {
4442 struct necp_kernel_socket_policy *kernel_policy = NULL;
4443 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4444
4445 if (policy_id == 0) {
4446 return NULL;
4447 }
4448
4449 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
4450 if (kernel_policy->id == policy_id) {
4451 return kernel_policy;
4452 }
4453 }
4454
4455 return NULL;
4456 }
4457
4458 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)4459 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
4460 {
4461 struct necp_kernel_socket_policy *policy = NULL;
4462
4463 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4464
4465 policy = necp_kernel_socket_policy_find(policy_id);
4466 if (policy) {
4467 LIST_REMOVE(policy, chain);
4468
4469 if (policy->cond_bound_interface) {
4470 ifnet_release(policy->cond_bound_interface);
4471 policy->cond_bound_interface = NULL;
4472 }
4473
4474 if (policy->cond_domain) {
4475 kfree_data_addr(policy->cond_domain);
4476 policy->cond_domain = NULL;
4477 }
4478
4479 if (policy->cond_custom_entitlement) {
4480 kfree_data_addr(policy->cond_custom_entitlement);
4481 policy->cond_custom_entitlement = NULL;
4482 }
4483
4484 if (policy->cond_signing_identifier) {
4485 kfree_data_addr(policy->cond_signing_identifier);
4486 policy->cond_signing_identifier = NULL;
4487 }
4488
4489 zfree(necp_socket_policy_zone, policy);
4490 return TRUE;
4491 }
4492
4493 return FALSE;
4494 }
4495
4496 static inline const char *
necp_get_result_description(char * result_string,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)4497 necp_get_result_description(char *result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
4498 {
4499 uuid_string_t uuid_string;
4500 switch (result) {
4501 case NECP_KERNEL_POLICY_RESULT_NONE: {
4502 snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
4503 break;
4504 }
4505 case NECP_KERNEL_POLICY_RESULT_PASS: {
4506 snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
4507 break;
4508 }
4509 case NECP_KERNEL_POLICY_RESULT_SKIP: {
4510 snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
4511 break;
4512 }
4513 case NECP_KERNEL_POLICY_RESULT_DROP: {
4514 snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
4515 break;
4516 }
4517 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
4518 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
4519 break;
4520 }
4521 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
4522 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
4523 break;
4524 }
4525 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
4526 ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
4527 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
4528 break;
4529 }
4530 case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
4531 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
4532 break;
4533 }
4534 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
4535 ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
4536 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
4537 break;
4538 }
4539 case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
4540 snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
4541 break;
4542 }
4543 case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
4544 snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
4545 break;
4546 }
4547 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
4548 int index = 0;
4549 char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
4550 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
4551 if (route_rule != NULL) {
4552 for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
4553 if (route_rule->exception_if_indices[index] != 0) {
4554 ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
4555 snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
4556 } else {
4557 memset(interface_names[index], 0, IFXNAMSIZ);
4558 }
4559 }
4560 switch (route_rule->default_action) {
4561 case NECP_ROUTE_RULE_DENY_INTERFACE:
4562 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)",
4563 (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
4564 (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
4565 (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
4566 (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
4567 (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
4568 (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
4569 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
4570 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4571 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
4572 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4573 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
4574 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4575 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
4576 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4577 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
4578 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4579 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
4580 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4581 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
4582 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4583 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
4584 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4585 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
4586 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4587 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
4588 break;
4589 case NECP_ROUTE_RULE_ALLOW_INTERFACE:
4590 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)",
4591 (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!Cell " : "",
4592 (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!WiFi " : "",
4593 (route_rule->wired_action == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!Wired " : "",
4594 (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!Exp " : "",
4595 (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!Constrained " : "",
4596 (route_rule->companion_action == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!Companion " : "",
4597 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4598 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[0] : "",
4599 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4600 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[1] : "",
4601 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4602 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[2] : "",
4603 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4604 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[3] : "",
4605 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4606 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[4] : "",
4607 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4608 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[5] : "",
4609 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4610 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[6] : "",
4611 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4612 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[7] : "",
4613 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4614 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[8] : "",
4615 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_DENY_INTERFACE) ? "!" : "",
4616 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_DENY_INTERFACE) ? interface_names[9] : "");
4617 break;
4618 case NECP_ROUTE_RULE_QOS_MARKING:
4619 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)",
4620 (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
4621 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
4622 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
4623 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
4624 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
4625 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
4626 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
4627 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4628 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
4629 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4630 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
4631 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4632 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
4633 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4634 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
4635 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4636 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
4637 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4638 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
4639 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4640 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
4641 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4642 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
4643 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4644 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
4645 break;
4646 default:
4647 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
4648 break;
4649 }
4650 }
4651 break;
4652 }
4653 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
4654 bool found_mapping = FALSE;
4655 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
4656 if (mapping != NULL) {
4657 uuid_unparse(mapping->uuid, uuid_string);
4658 found_mapping = TRUE;
4659 }
4660 snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
4661 break;
4662 }
4663 case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
4664 bool found_mapping = FALSE;
4665 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
4666 if (mapping != NULL) {
4667 uuid_unparse(mapping->uuid, uuid_string);
4668 found_mapping = TRUE;
4669 }
4670 snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
4671 break;
4672 }
4673 case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
4674 bool found_mapping = FALSE;
4675 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
4676 if (mapping != NULL) {
4677 uuid_unparse(mapping->uuid, uuid_string);
4678 found_mapping = TRUE;
4679 }
4680 snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
4681 break;
4682 }
4683 default: {
4684 snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
4685 break;
4686 }
4687 }
4688 return result_string;
4689 }
4690
4691 static void
necp_kernel_socket_policies_dump_all(void)4692 necp_kernel_socket_policies_dump_all(void)
4693 {
4694 if (necp_debug) {
4695 struct necp_kernel_socket_policy *policy = NULL;
4696 int policy_i;
4697 int app_i;
4698 char result_string[MAX_RESULT_STRING_LEN];
4699 char proc_name_string[MAXCOMLEN + 1];
4700 memset(result_string, 0, MAX_RESULT_STRING_LEN);
4701 memset(proc_name_string, 0, MAXCOMLEN + 1);
4702
4703 NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
4704 NECPLOG0(LOG_DEBUG, "-----------\n");
4705 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
4706 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
4707 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
4708 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));
4709 }
4710 if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
4711 NECPLOG0(LOG_DEBUG, "-----------\n");
4712 }
4713
4714 NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
4715 NECPLOG0(LOG_DEBUG, "-----------\n");
4716 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
4717 NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
4718 for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
4719 policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
4720 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
4721 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));
4722 }
4723 NECPLOG0(LOG_DEBUG, "-----------\n");
4724 }
4725 }
4726 }
4727
4728 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)4729 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
4730 {
4731 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
4732 // Drop always cancels out lower policies
4733 return TRUE;
4734 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
4735 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
4736 upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
4737 upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
4738 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
4739 upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
4740 // Filters and route rules never cancel out lower policies
4741 return FALSE;
4742 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
4743 if (upper_policy->session_order != lower_policy->session_order) {
4744 // A skip cannot override a policy of a different session
4745 return FALSE;
4746 } else {
4747 if (upper_policy->result_parameter.skip_policy_order == 0 ||
4748 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
4749 // This policy is beyond the skip
4750 return FALSE;
4751 } else {
4752 // This policy is inside the skip
4753 return TRUE;
4754 }
4755 }
4756 }
4757
4758 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
4759 return TRUE;
4760 }
4761
4762 static bool
necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy * policy,struct necp_kernel_socket_policy ** policy_array,int valid_indices)4763 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy **policy_array, int valid_indices)
4764 {
4765 bool can_skip = FALSE;
4766 u_int32_t highest_skip_session_order = 0;
4767 u_int32_t highest_skip_order = 0;
4768 int i;
4769 for (i = 0; i < valid_indices; i++) {
4770 struct necp_kernel_socket_policy *compared_policy = policy_array[i];
4771
4772 // For policies in a skip window, we can't mark conflicting policies as unnecessary
4773 if (can_skip) {
4774 if (highest_skip_session_order != compared_policy->session_order ||
4775 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
4776 // If we've moved on to the next session, or passed the skip window
4777 highest_skip_session_order = 0;
4778 highest_skip_order = 0;
4779 can_skip = FALSE;
4780 } else {
4781 // If this policy is also a skip, in can increase the skip window
4782 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
4783 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
4784 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
4785 }
4786 }
4787 continue;
4788 }
4789 }
4790
4791 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
4792 // This policy is a skip. Set the skip window accordingly
4793 can_skip = TRUE;
4794 highest_skip_session_order = compared_policy->session_order;
4795 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
4796 }
4797
4798 // The result of the compared policy must be able to block out this policy result
4799 if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
4800 continue;
4801 }
4802
4803 // If new policy matches All Interfaces, compared policy must also
4804 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
4805 continue;
4806 }
4807
4808 // If new policy matches Local Networks, compared policy must also
4809 if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
4810 continue;
4811 }
4812
4813 // Default makes lower policies unecessary always
4814 if (compared_policy->condition_mask == 0) {
4815 return TRUE;
4816 }
4817
4818 // Compared must be more general than policy, and include only conditions within policy
4819 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
4820 continue;
4821 }
4822
4823 // Negative conditions must match for the overlapping conditions
4824 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
4825 continue;
4826 }
4827
4828 if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
4829 compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
4830 strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
4831 continue;
4832 }
4833
4834 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
4835 compared_policy->cond_domain_filter != policy->cond_domain_filter) {
4836 continue;
4837 }
4838
4839 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
4840 strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
4841 continue;
4842 }
4843
4844 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
4845 compared_policy->cond_account_id != policy->cond_account_id) {
4846 continue;
4847 }
4848
4849 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
4850 compared_policy->cond_policy_id != policy->cond_policy_id) {
4851 continue;
4852 }
4853
4854 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
4855 compared_policy->cond_app_id != policy->cond_app_id) {
4856 continue;
4857 }
4858
4859 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
4860 compared_policy->cond_real_app_id != policy->cond_real_app_id) {
4861 continue;
4862 }
4863
4864 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
4865 (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
4866 continue;
4867 }
4868
4869 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
4870 compared_policy->cond_uid != policy->cond_uid) {
4871 continue;
4872 }
4873
4874 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
4875 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
4876 continue;
4877 }
4878
4879 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
4880 compared_policy->cond_protocol != policy->cond_protocol) {
4881 continue;
4882 }
4883
4884 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
4885 compared_policy->cond_client_flags != policy->cond_client_flags) {
4886 continue;
4887 }
4888
4889 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
4890 !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
4891 compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
4892 continue;
4893 }
4894
4895 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4896 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4897 if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&policy->cond_local_end, (struct sockaddr *)&compared_policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_end)) {
4898 continue;
4899 }
4900 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4901 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
4902 !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_start, compared_policy->cond_local_prefix)) {
4903 continue;
4904 }
4905 }
4906 }
4907
4908 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4909 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4910 if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&policy->cond_remote_end, (struct sockaddr *)&compared_policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_end)) {
4911 continue;
4912 }
4913 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4914 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
4915 !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_start, compared_policy->cond_remote_prefix)) {
4916 continue;
4917 }
4918 }
4919 }
4920
4921 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
4922 memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
4923 continue;
4924 }
4925
4926 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
4927 memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
4928 continue;
4929 }
4930
4931 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
4932 memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
4933 continue;
4934 }
4935
4936 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
4937 memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
4938 continue;
4939 }
4940
4941 return TRUE;
4942 }
4943
4944 return FALSE;
4945 }
4946
4947 static bool
necp_kernel_socket_policies_reprocess(void)4948 necp_kernel_socket_policies_reprocess(void)
4949 {
4950 int app_i;
4951 int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
4952 int app_layer_current_free_index = 0;
4953 struct necp_kernel_socket_policy *kernel_policy = NULL;
4954
4955 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4956
4957 // Reset mask to 0
4958 necp_kernel_application_policies_condition_mask = 0;
4959 necp_kernel_socket_policies_condition_mask = 0;
4960 necp_kernel_application_policies_count = 0;
4961 necp_kernel_socket_policies_count = 0;
4962 necp_kernel_socket_policies_non_app_count = 0;
4963
4964 // Reset all maps to NULL
4965 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
4966 if (necp_kernel_socket_policies_map[app_i] != NULL) {
4967 kfree_type(struct necp_kernel_socket_policy *,
4968 necp_kernel_socket_policies_map_counts[app_i] + 1,
4969 necp_kernel_socket_policies_map[app_i]);
4970 necp_kernel_socket_policies_map[app_i] = NULL;
4971 }
4972
4973 // Init counts
4974 necp_kernel_socket_policies_map_counts[app_i] = 0;
4975 }
4976 if (necp_kernel_socket_policies_app_layer_map != NULL) {
4977 kfree_type(struct necp_kernel_socket_policy *,
4978 necp_kernel_socket_policies_app_layer_map_count + 1,
4979 necp_kernel_socket_policies_app_layer_map);
4980 }
4981 necp_kernel_socket_policies_app_layer_map = NULL;
4982 necp_kernel_socket_policies_app_layer_map_count = 0;
4983
4984 // Create masks and counts
4985 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
4986 // App layer mask/count
4987 necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
4988 necp_kernel_application_policies_count++;
4989 necp_kernel_socket_policies_app_layer_map_count++;
4990
4991 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
4992 // Agent type conditions only apply to app layer
4993 continue;
4994 }
4995
4996 // Update socket layer bucket mask/counts
4997 necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
4998 necp_kernel_socket_policies_count++;
4999
5000 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5001 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5002 necp_kernel_socket_policies_non_app_count++;
5003 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5004 necp_kernel_socket_policies_map_counts[app_i]++;
5005 }
5006 } else {
5007 necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5008 }
5009 }
5010
5011 // Allocate maps
5012 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5013 if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5014 // Allocate a NULL-terminated array of policy pointers for each bucket
5015 necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5016 necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5017 if (necp_kernel_socket_policies_map[app_i] == NULL) {
5018 goto fail;
5019 }
5020 }
5021 bucket_current_free_index[app_i] = 0;
5022 }
5023 necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5024 necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5025 if (necp_kernel_socket_policies_app_layer_map == NULL) {
5026 goto fail;
5027 }
5028
5029 // Fill out maps
5030 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5031 // Add app layer policies
5032 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5033 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5034 app_layer_current_free_index++;
5035 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5036 }
5037
5038 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5039 // Agent type conditions only apply to app layer
5040 continue;
5041 }
5042
5043 // Add socket policies
5044 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5045 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5046 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5047 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])) {
5048 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5049 bucket_current_free_index[app_i]++;
5050 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5051 }
5052 }
5053 } else {
5054 app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5055 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])) {
5056 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5057 bucket_current_free_index[app_i]++;
5058 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5059 }
5060 }
5061 }
5062 necp_kernel_socket_policies_dump_all();
5063 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5064 return TRUE;
5065
5066 fail:
5067 // Free memory, reset masks to 0
5068 necp_kernel_application_policies_condition_mask = 0;
5069 necp_kernel_socket_policies_condition_mask = 0;
5070 necp_kernel_application_policies_count = 0;
5071 necp_kernel_socket_policies_count = 0;
5072 necp_kernel_socket_policies_non_app_count = 0;
5073 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5074 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5075 kfree_type(struct necp_kernel_socket_policy *,
5076 necp_kernel_socket_policies_map_counts[app_i] + 1,
5077 necp_kernel_socket_policies_map[app_i]);
5078 necp_kernel_socket_policies_map[app_i] = NULL;
5079 }
5080 necp_kernel_socket_policies_map_counts[app_i] = 0;
5081 }
5082 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5083 kfree_type(struct necp_kernel_socket_policy *,
5084 necp_kernel_socket_policies_app_layer_map_count + 1,
5085 necp_kernel_socket_policies_app_layer_map);
5086 necp_kernel_socket_policies_app_layer_map = NULL;
5087 }
5088 necp_kernel_socket_policies_app_layer_map_count = 0;
5089 return FALSE;
5090 }
5091
5092 static u_int32_t
necp_get_new_string_id(void)5093 necp_get_new_string_id(void)
5094 {
5095 static u_int32_t necp_last_string_id = 0;
5096
5097 u_int32_t newid = 0;
5098
5099 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5100
5101 bool wrapped = FALSE;
5102 do {
5103 necp_last_string_id++;
5104 if (necp_last_string_id < 1) {
5105 if (wrapped) {
5106 // Already wrapped, give up
5107 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5108 return 0;
5109 }
5110 necp_last_string_id = 1;
5111 wrapped = TRUE;
5112 }
5113 newid = necp_last_string_id;
5114 } while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5115
5116 if (newid == 0) {
5117 NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5118 return 0;
5119 }
5120
5121 return newid;
5122 }
5123
5124 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string)5125 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string)
5126 {
5127 struct necp_string_id_mapping *searchentry = NULL;
5128 struct necp_string_id_mapping *foundentry = NULL;
5129
5130 LIST_FOREACH(searchentry, list, chain) {
5131 if (strcmp(searchentry->string, string) == 0) {
5132 foundentry = searchentry;
5133 break;
5134 }
5135 }
5136
5137 return foundentry;
5138 }
5139
5140 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5141 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5142 {
5143 struct necp_string_id_mapping *searchentry = NULL;
5144 struct necp_string_id_mapping *foundentry = NULL;
5145
5146 LIST_FOREACH(searchentry, list, chain) {
5147 if (searchentry->id == local_id) {
5148 foundentry = searchentry;
5149 break;
5150 }
5151 }
5152
5153 return foundentry;
5154 }
5155
5156 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string)5157 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
5158 {
5159 u_int32_t string_id = 0;
5160 struct necp_string_id_mapping *existing_mapping = NULL;
5161
5162 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5163
5164 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5165 if (existing_mapping != NULL) {
5166 string_id = existing_mapping->id;
5167 os_ref_retain_locked(&existing_mapping->refcount);
5168 } else {
5169 struct necp_string_id_mapping *new_mapping = NULL;
5170 new_mapping = kalloc_type(struct necp_string_id_mapping,
5171 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5172
5173 size_t length = strlen(string) + 1;
5174 new_mapping->string = (char *)kalloc_data(length, Z_WAITOK);
5175 if (new_mapping->string != NULL) {
5176 memcpy(new_mapping->string, string, length);
5177 new_mapping->id = necp_get_new_string_id();
5178 os_ref_init(&new_mapping->refcount, &necp_refgrp);
5179 LIST_INSERT_HEAD(list, new_mapping, chain);
5180 string_id = new_mapping->id;
5181 } else {
5182 kfree_type(struct necp_string_id_mapping, new_mapping);
5183 new_mapping = NULL;
5184 }
5185 }
5186 return string_id;
5187 }
5188
5189 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string)5190 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
5191 {
5192 struct necp_string_id_mapping *existing_mapping = NULL;
5193
5194 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5195
5196 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5197 if (existing_mapping != NULL) {
5198 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5199 LIST_REMOVE(existing_mapping, chain);
5200 kfree_data_addr(existing_mapping->string);
5201 kfree_type(struct necp_string_id_mapping, existing_mapping);
5202 }
5203 return TRUE;
5204 }
5205
5206 return FALSE;
5207 }
5208
5209 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5210 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5211 {
5212 struct necp_domain_filter *searchfilter = NULL;
5213 struct necp_domain_filter *foundfilter = NULL;
5214
5215 LIST_FOREACH(searchfilter, list, chain) {
5216 if (searchfilter->id == filter_id) {
5217 foundfilter = searchfilter;
5218 break;
5219 }
5220 }
5221
5222 return foundfilter;
5223 }
5224
5225 static u_int32_t
necp_get_new_domain_filter_id(void)5226 necp_get_new_domain_filter_id(void)
5227 {
5228 static u_int32_t necp_last_filter_id = 0;
5229
5230 u_int32_t newid = 0;
5231
5232 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5233
5234 bool wrapped = FALSE;
5235 do {
5236 necp_last_filter_id++;
5237 if (necp_last_filter_id < 1) {
5238 if (wrapped) {
5239 // Already wrapped, give up
5240 NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5241 return 0;
5242 }
5243 necp_last_filter_id = 1;
5244 wrapped = TRUE;
5245 }
5246 newid = necp_last_filter_id;
5247 } while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5248
5249 if (newid == 0) {
5250 NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5251 return 0;
5252 }
5253
5254 return newid;
5255 }
5256
5257 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)5258 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5259 {
5260 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5261
5262 struct necp_domain_filter *new_filter = NULL;
5263 new_filter = kalloc_type(struct necp_domain_filter,
5264 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5265
5266 new_filter->filter = filter;
5267 new_filter->id = necp_get_new_domain_filter_id();
5268 LIST_INSERT_HEAD(list, new_filter, chain);
5269 LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
5270 os_ref_init(&new_filter->refcount, &necp_refgrp);
5271
5272 return new_filter->id;
5273 }
5274
5275 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)5276 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
5277 {
5278 struct necp_domain_filter *existing_filter = NULL;
5279
5280 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5281
5282 existing_filter = necp_lookup_domain_filter(list, filter_id);
5283 if (existing_filter != NULL) {
5284 if (os_ref_release_locked(&existing_filter->refcount) == 0) {
5285 LIST_REMOVE(existing_filter, chain);
5286 LIST_REMOVE(existing_filter, owner_chain);
5287 net_bloom_filter_destroy(existing_filter->filter);
5288 kfree_type(struct necp_domain_filter, existing_filter);
5289 }
5290 return true;
5291 }
5292
5293 return false;
5294 }
5295
5296 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
5297 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
5298 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)5299 necp_get_new_route_rule_id(bool aggregate)
5300 {
5301 static u_int32_t necp_last_route_rule_id = 0;
5302 static u_int32_t necp_last_aggregate_route_rule_id = 0;
5303
5304 u_int32_t newid = 0;
5305
5306 if (!aggregate) {
5307 // Main necp_kernel_policy_lock protects non-aggregate rule IDs
5308 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5309
5310 bool wrapped = FALSE;
5311 do {
5312 necp_last_route_rule_id++;
5313 if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
5314 necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5315 if (wrapped) {
5316 // Already wrapped, give up
5317 NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
5318 return 0;
5319 }
5320 necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
5321 wrapped = TRUE;
5322 }
5323 newid = necp_last_route_rule_id;
5324 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
5325 } else {
5326 // necp_route_rule_lock protects aggregate rule IDs
5327 LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
5328
5329 bool wrapped = FALSE;
5330 do {
5331 necp_last_aggregate_route_rule_id++;
5332 if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5333 if (wrapped) {
5334 // Already wrapped, give up
5335 NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
5336 return 0;
5337 }
5338 necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
5339 wrapped = TRUE;
5340 }
5341 newid = necp_last_aggregate_route_rule_id;
5342 } while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
5343 }
5344
5345 if (newid == 0) {
5346 NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
5347 return 0;
5348 }
5349
5350 return newid;
5351 }
5352
5353 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)5354 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
5355 {
5356 struct necp_route_rule *searchentry = NULL;
5357 struct necp_route_rule *foundentry = NULL;
5358
5359 LIST_FOREACH(searchentry, list, chain) {
5360 if (searchentry->id == route_rule_id) {
5361 foundentry = searchentry;
5362 break;
5363 }
5364 }
5365
5366 return foundentry;
5367 }
5368
5369 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_int32_t * if_indices,u_int8_t * if_actions,uuid_t netagent_uuid,uuid_t match_netagent_uuid,u_int32_t control_unit)5370 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_int32_t *if_indices, u_int8_t *if_actions, uuid_t netagent_uuid, uuid_t match_netagent_uuid, u_int32_t control_unit)
5371 {
5372 struct necp_route_rule *searchentry = NULL;
5373 struct necp_route_rule *foundentry = NULL;
5374
5375 LIST_FOREACH(searchentry, list, chain) {
5376 if (searchentry->default_action == default_action &&
5377 searchentry->cellular_action == cellular_action &&
5378 searchentry->wifi_action == wifi_action &&
5379 searchentry->wired_action == wired_action &&
5380 searchentry->expensive_action == expensive_action &&
5381 searchentry->constrained_action == constrained_action &&
5382 searchentry->companion_action == companion_action &&
5383 searchentry->control_unit == control_unit) {
5384 bool match_failed = FALSE;
5385 size_t index_a = 0;
5386 size_t index_b = 0;
5387 size_t count_a = 0;
5388 size_t count_b = 0;
5389 for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
5390 bool found_index = FALSE;
5391 if (searchentry->exception_if_indices[index_a] == 0) {
5392 break;
5393 }
5394 count_a++;
5395 for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
5396 if (if_indices[index_b] == 0) {
5397 break;
5398 }
5399 if (index_b >= count_b) {
5400 count_b = index_b + 1;
5401 }
5402 if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
5403 searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
5404 found_index = TRUE;
5405 break;
5406 }
5407 }
5408 if (!found_index) {
5409 match_failed = TRUE;
5410 break;
5411 }
5412 }
5413
5414 if (match_failed || count_a != count_b) {
5415 continue;
5416 }
5417
5418 bool has_agent_a = !uuid_is_null(netagent_uuid);
5419 bool has_agent_b = (searchentry->netagent_id != 0);
5420 if (has_agent_a != has_agent_b) {
5421 continue;
5422 }
5423
5424 if (has_agent_a) {
5425 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
5426 if (mapping == NULL) {
5427 // Bad mapping, doesn't match
5428 continue;
5429 }
5430 if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
5431 // UUIDs don't match
5432 continue;
5433 }
5434 }
5435
5436 bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
5437 bool has_match_agent_b = (searchentry->match_netagent_id != 0);
5438 if (has_match_agent_a != has_match_agent_b) {
5439 continue;
5440 }
5441
5442 if (has_match_agent_a) {
5443 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->match_netagent_id);
5444 if (mapping == NULL) {
5445 // Bad mapping, doesn't match
5446 continue;
5447 }
5448 if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
5449 // UUIDs don't match
5450 continue;
5451 }
5452 }
5453
5454 // Rules match!
5455 foundentry = searchentry;
5456 break;
5457 }
5458 }
5459
5460 return foundentry;
5461 }
5462
5463 static u_int32_t
necp_create_route_rule(struct necp_route_rule_list * list,u_int8_t * route_rules_array,u_int32_t route_rules_array_size)5464 necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t *route_rules_array, u_int32_t route_rules_array_size)
5465 {
5466 size_t offset = 0;
5467 u_int32_t route_rule_id = 0;
5468 struct necp_route_rule *existing_rule = NULL;
5469 u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
5470 u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
5471 u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
5472 u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
5473 u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
5474 u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
5475 u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
5476 u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
5477 size_t num_valid_indices = 0;
5478 memset(&if_indices, 0, sizeof(if_indices));
5479 u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
5480 memset(&if_actions, 0, sizeof(if_actions));
5481
5482 uuid_t netagent_uuid = {};
5483
5484 uuid_t match_netagent_uuid = {};
5485 uint32_t control_unit = 0;
5486
5487 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5488
5489 if (route_rules_array == NULL || route_rules_array_size == 0) {
5490 return 0;
5491 }
5492
5493 // Process rules
5494 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
5495 ifnet_t rule_interface = NULL;
5496 char interface_name[IFXNAMSIZ];
5497 u_int32_t length = 0;
5498 u_int8_t *value = necp_buffer_get_tlv_value(route_rules_array, offset, &length);
5499
5500 if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
5501 // Invalid TLV goes beyond end of the rules array
5502 break;
5503 }
5504
5505 // Increment offset for the next time through the loop
5506 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
5507
5508 u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
5509 u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
5510 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
5511 u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
5512
5513 if (rule_action == NECP_ROUTE_RULE_NONE) {
5514 // Don't allow an explicit rule to be None action
5515 continue;
5516 }
5517
5518 if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
5519 rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
5520 if (rule_length < sizeof(uuid_t)) {
5521 // Too short, skip
5522 continue;
5523 }
5524
5525 if (!uuid_is_null(netagent_uuid)) {
5526 if (uuid_compare(netagent_uuid, rule_value) != 0) {
5527 // UUIDs don't match, skip
5528 continue;
5529 }
5530 } else {
5531 // Copy out agent UUID
5532 memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
5533 }
5534
5535 // Adjust remaining length
5536 rule_value += sizeof(netagent_uuid);
5537 rule_length -= sizeof(netagent_uuid);
5538 } else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
5539 if (rule_length < sizeof(control_unit)) {
5540 // Too short, skip
5541 continue;
5542 }
5543
5544 memcpy(&control_unit, rule_value, sizeof(control_unit));
5545
5546 // Adjust remaining length
5547 rule_value += sizeof(control_unit);
5548 rule_length -= sizeof(control_unit);
5549 }
5550
5551 if (rule_length == 0) {
5552 if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
5553 cellular_action = rule_action;
5554 }
5555 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
5556 wifi_action = rule_action;
5557 }
5558 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
5559 wired_action = rule_action;
5560 }
5561 if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
5562 expensive_action = rule_action;
5563 }
5564 if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
5565 constrained_action = rule_action;
5566 }
5567 if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
5568 companion_action = rule_action;
5569 }
5570 if (rule_flags == 0) {
5571 default_action = rule_action;
5572 }
5573 continue;
5574 } else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
5575 if (rule_length == sizeof(uuid_t)) {
5576 memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
5577 default_action = rule_action;
5578 }
5579 continue;
5580 }
5581
5582 if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
5583 continue;
5584 }
5585
5586 if (rule_length <= IFXNAMSIZ) {
5587 memcpy(interface_name, rule_value, rule_length);
5588 interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
5589 if (ifnet_find_by_name(interface_name, &rule_interface) == 0) {
5590 if_actions[num_valid_indices] = rule_action;
5591 if_indices[num_valid_indices++] = rule_interface->if_index;
5592 ifnet_release(rule_interface);
5593 }
5594 }
5595 }
5596
5597 existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, companion_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit);
5598 if (existing_rule != NULL) {
5599 route_rule_id = existing_rule->id;
5600 os_ref_retain_locked(&existing_rule->refcount);
5601 } else {
5602 struct necp_route_rule *new_rule = NULL;
5603 new_rule = kalloc_type(struct necp_route_rule,
5604 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5605 route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
5606 if (!uuid_is_null(netagent_uuid)) {
5607 new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
5608 }
5609 if (!uuid_is_null(match_netagent_uuid)) {
5610 new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(match_netagent_uuid);
5611 }
5612 new_rule->control_unit = control_unit;
5613 new_rule->default_action = default_action;
5614 new_rule->cellular_action = cellular_action;
5615 new_rule->wifi_action = wifi_action;
5616 new_rule->wired_action = wired_action;
5617 new_rule->expensive_action = expensive_action;
5618 new_rule->constrained_action = constrained_action;
5619 new_rule->companion_action = companion_action;
5620 memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
5621 memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
5622 os_ref_init(&new_rule->refcount, &necp_refgrp);
5623 LIST_INSERT_HEAD(list, new_rule, chain);
5624 }
5625 return route_rule_id;
5626 }
5627
5628 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)5629 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
5630 {
5631 if (rule_id) {
5632 lck_rw_lock_exclusive(&necp_route_rule_lock);
5633
5634 struct necp_aggregate_route_rule *existing_rule = NULL;
5635 struct necp_aggregate_route_rule *tmp_rule = NULL;
5636
5637 LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
5638 int index = 0;
5639 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
5640 u_int32_t route_rule_id = existing_rule->rule_ids[index];
5641 if (route_rule_id == rule_id) {
5642 LIST_REMOVE(existing_rule, chain);
5643 kfree_type(struct necp_aggregate_route_rule, existing_rule);
5644 break;
5645 }
5646 }
5647 }
5648
5649 lck_rw_done(&necp_route_rule_lock);
5650 }
5651 }
5652
5653 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)5654 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
5655 {
5656 struct necp_route_rule *existing_rule = NULL;
5657
5658 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5659
5660 existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
5661 if (existing_rule != NULL) {
5662 if (os_ref_release_locked(&existing_rule->refcount) == 0) {
5663 necp_remove_aggregate_route_rule_for_id(existing_rule->id);
5664 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
5665 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->match_netagent_id);
5666 LIST_REMOVE(existing_rule, chain);
5667 kfree_type(struct necp_route_rule, existing_rule);
5668 }
5669 return TRUE;
5670 }
5671
5672 return FALSE;
5673 }
5674
5675 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)5676 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
5677 {
5678 struct necp_aggregate_route_rule *searchentry = NULL;
5679 struct necp_aggregate_route_rule *foundentry = NULL;
5680
5681 lck_rw_lock_shared(&necp_route_rule_lock);
5682
5683 LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
5684 if (searchentry->id == route_rule_id) {
5685 foundentry = searchentry;
5686 break;
5687 }
5688 }
5689
5690 lck_rw_done(&necp_route_rule_lock);
5691
5692 return foundentry;
5693 }
5694
5695 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * rule_ids)5696 necp_create_aggregate_route_rule(u_int32_t *rule_ids)
5697 {
5698 u_int32_t aggregate_route_rule_id = 0;
5699 struct necp_aggregate_route_rule *new_rule = NULL;
5700 struct necp_aggregate_route_rule *existing_rule = NULL;
5701
5702 lck_rw_lock_exclusive(&necp_route_rule_lock);
5703
5704 // Check if the rule already exists
5705 LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
5706 if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
5707 lck_rw_done(&necp_route_rule_lock);
5708 return existing_rule->id;
5709 }
5710 }
5711
5712 new_rule = kalloc_type(struct necp_aggregate_route_rule,
5713 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5714 aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
5715 new_rule->id = aggregate_route_rule_id;
5716 memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
5717 LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
5718 lck_rw_done(&necp_route_rule_lock);
5719
5720 return aggregate_route_rule_id;
5721 }
5722
5723 #define NECP_NULL_SERVICE_ID 1
5724 #define NECP_FIRST_VALID_SERVICE_ID 2
5725 #define NECP_FIRST_VALID_APP_ID UINT16_MAX
5726 static u_int32_t
necp_get_new_uuid_id(bool service)5727 necp_get_new_uuid_id(bool service)
5728 {
5729 static u_int32_t necp_last_service_uuid_id = 0;
5730 static u_int32_t necp_last_app_uuid_id = 0;
5731
5732 u_int32_t newid = 0;
5733
5734 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5735
5736 if (service) {
5737 bool wrapped = FALSE;
5738 do {
5739 necp_last_service_uuid_id++;
5740 if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
5741 necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
5742 if (wrapped) {
5743 // Already wrapped, give up
5744 NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
5745 return NECP_NULL_SERVICE_ID;
5746 }
5747 necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
5748 wrapped = TRUE;
5749 }
5750 newid = necp_last_service_uuid_id;
5751 } while (necp_uuid_lookup_uuid_with_service_id_locked(newid) != NULL); // If already used, keep trying
5752 } else {
5753 bool wrapped = FALSE;
5754 do {
5755 necp_last_app_uuid_id++;
5756 if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
5757 if (wrapped) {
5758 // Already wrapped, give up
5759 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5760 return NECP_NULL_SERVICE_ID;
5761 }
5762 necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
5763 wrapped = TRUE;
5764 }
5765 newid = necp_last_app_uuid_id;
5766 } while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
5767 }
5768
5769 if (newid == NECP_NULL_SERVICE_ID) {
5770 NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
5771 return NECP_NULL_SERVICE_ID;
5772 }
5773
5774 return newid;
5775 }
5776
5777 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)5778 necp_uuid_lookup_app_id_locked(uuid_t uuid)
5779 {
5780 struct necp_uuid_id_mapping *searchentry = NULL;
5781 struct necp_uuid_id_mapping *foundentry = NULL;
5782
5783 LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
5784 if (uuid_compare(searchentry->uuid, uuid) == 0) {
5785 foundentry = searchentry;
5786 break;
5787 }
5788 }
5789
5790 return foundentry;
5791 }
5792
5793 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)5794 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
5795 {
5796 struct necp_uuid_id_mapping *searchentry = NULL;
5797 struct necp_uuid_id_mapping *foundentry = NULL;
5798
5799 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
5800 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--) {
5801 LIST_FOREACH(searchentry, uuid_list_head, chain) {
5802 if (searchentry->id == local_id) {
5803 foundentry = searchentry;
5804 break;
5805 }
5806 }
5807 }
5808
5809 return foundentry;
5810 }
5811
5812 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)5813 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
5814 {
5815 u_int32_t local_id = 0;
5816 struct necp_uuid_id_mapping *existing_mapping = NULL;
5817
5818 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5819
5820 if (allocated_mapping) {
5821 *allocated_mapping = FALSE;
5822 }
5823
5824 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
5825 if (existing_mapping != NULL) {
5826 local_id = existing_mapping->id;
5827 os_ref_retain_locked(&existing_mapping->refcount);
5828 if (uuid_policy_table) {
5829 existing_mapping->table_usecount++;
5830 }
5831 } else {
5832 struct necp_uuid_id_mapping *new_mapping = NULL;
5833 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
5834 Z_WAITOK | Z_NOFAIL);
5835 uuid_copy(new_mapping->uuid, uuid);
5836 new_mapping->id = necp_get_new_uuid_id(false);
5837 os_ref_init(&new_mapping->refcount, &necp_refgrp);
5838 if (uuid_policy_table) {
5839 new_mapping->table_usecount = 1;
5840 } else {
5841 new_mapping->table_usecount = 0;
5842 }
5843
5844 LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
5845
5846 if (allocated_mapping) {
5847 *allocated_mapping = TRUE;
5848 }
5849
5850 local_id = new_mapping->id;
5851 }
5852
5853 return local_id;
5854 }
5855
5856 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)5857 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
5858 {
5859 struct necp_uuid_id_mapping *existing_mapping = NULL;
5860
5861 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5862
5863 if (removed_mapping) {
5864 *removed_mapping = FALSE;
5865 }
5866
5867 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
5868 if (existing_mapping != NULL) {
5869 if (uuid_policy_table) {
5870 existing_mapping->table_usecount--;
5871 }
5872 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5873 LIST_REMOVE(existing_mapping, chain);
5874 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
5875 if (removed_mapping) {
5876 *removed_mapping = TRUE;
5877 }
5878 }
5879 return TRUE;
5880 }
5881
5882 return FALSE;
5883 }
5884
5885 static struct necp_uuid_id_mapping *
necp_uuid_get_null_service_id_mapping(void)5886 necp_uuid_get_null_service_id_mapping(void)
5887 {
5888 static struct necp_uuid_id_mapping null_mapping;
5889 uuid_clear(null_mapping.uuid);
5890 null_mapping.id = NECP_NULL_SERVICE_ID;
5891
5892 return &null_mapping;
5893 }
5894
5895 static struct necp_uuid_id_mapping *
necp_uuid_lookup_service_id_locked(uuid_t uuid)5896 necp_uuid_lookup_service_id_locked(uuid_t uuid)
5897 {
5898 struct necp_uuid_id_mapping *searchentry = NULL;
5899 struct necp_uuid_id_mapping *foundentry = NULL;
5900
5901 if (uuid_is_null(uuid)) {
5902 return necp_uuid_get_null_service_id_mapping();
5903 }
5904
5905 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
5906 if (uuid_compare(searchentry->uuid, uuid) == 0) {
5907 foundentry = searchentry;
5908 break;
5909 }
5910 }
5911
5912 return foundentry;
5913 }
5914
5915 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)5916 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
5917 {
5918 struct necp_uuid_id_mapping *searchentry = NULL;
5919 struct necp_uuid_id_mapping *foundentry = NULL;
5920
5921 if (local_id == NECP_NULL_SERVICE_ID) {
5922 return necp_uuid_get_null_service_id_mapping();
5923 }
5924
5925 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
5926 if (searchentry->id == local_id) {
5927 foundentry = searchentry;
5928 break;
5929 }
5930 }
5931
5932 return foundentry;
5933 }
5934
5935 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid)5936 necp_create_uuid_service_id_mapping(uuid_t uuid)
5937 {
5938 u_int32_t local_id = 0;
5939 struct necp_uuid_id_mapping *existing_mapping = NULL;
5940
5941 if (uuid_is_null(uuid)) {
5942 return NECP_NULL_SERVICE_ID;
5943 }
5944
5945 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5946
5947 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
5948 if (existing_mapping != NULL) {
5949 local_id = existing_mapping->id;
5950 os_ref_retain_locked(&existing_mapping->refcount);
5951 } else {
5952 struct necp_uuid_id_mapping *new_mapping = NULL;
5953 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
5954 Z_WAITOK | Z_NOFAIL);
5955 uuid_copy(new_mapping->uuid, uuid);
5956 new_mapping->id = necp_get_new_uuid_id(true);
5957 os_ref_init(&new_mapping->refcount, &necp_refgrp);
5958
5959 LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
5960
5961 local_id = new_mapping->id;
5962 }
5963
5964 return local_id;
5965 }
5966
5967 static bool
necp_remove_uuid_service_id_mapping(uuid_t uuid)5968 necp_remove_uuid_service_id_mapping(uuid_t uuid)
5969 {
5970 struct necp_uuid_id_mapping *existing_mapping = NULL;
5971
5972 if (uuid_is_null(uuid)) {
5973 return TRUE;
5974 }
5975
5976 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5977
5978 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
5979 if (existing_mapping != NULL) {
5980 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5981 LIST_REMOVE(existing_mapping, chain);
5982 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
5983 }
5984 return TRUE;
5985 }
5986
5987 return FALSE;
5988 }
5989
5990 static bool
necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)5991 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
5992 {
5993 struct necp_uuid_id_mapping *existing_mapping = NULL;
5994
5995 if (service_id == 0) {
5996 return TRUE;
5997 }
5998
5999 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6000
6001 existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
6002 if (existing_mapping != NULL) {
6003 if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6004 LIST_REMOVE(existing_mapping, chain);
6005 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6006 }
6007 return TRUE;
6008 }
6009
6010 return FALSE;
6011 }
6012
6013 static bool
necp_kernel_socket_policies_update_uuid_table(void)6014 necp_kernel_socket_policies_update_uuid_table(void)
6015 {
6016 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6017
6018 if (necp_uuid_app_id_mappings_dirty) {
6019 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, NULL, PROC_UUID_NECP_APP_POLICY) < 0) {
6020 NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6021 return FALSE;
6022 }
6023
6024 if (necp_num_uuid_app_id_mappings > 0) {
6025 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6026 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--) {
6027 struct necp_uuid_id_mapping *mapping = NULL;
6028 LIST_FOREACH(mapping, uuid_list_head, chain) {
6029 if (mapping->table_usecount > 0 &&
6030 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6031 NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6032 }
6033 }
6034 }
6035 }
6036
6037 necp_uuid_app_id_mappings_dirty = FALSE;
6038 }
6039
6040 return TRUE;
6041 }
6042
6043 #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)
6044 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,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)6045 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, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
6046 {
6047 struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6048 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6049
6050 new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6051 new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6052 new_kernel_policy->suborder = suborder;
6053 new_kernel_policy->order = order;
6054 new_kernel_policy->session_order = session_order;
6055 new_kernel_policy->session_pid = session_pid;
6056
6057 // Sanitize condition mask
6058 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6059 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6060 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6061 }
6062 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6063 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6064 }
6065 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6066 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6067 }
6068 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6069
6070 // Set condition values
6071 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6072 new_kernel_policy->cond_policy_id = cond_policy_id;
6073 }
6074 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6075 if (cond_bound_interface) {
6076 ifnet_reference(cond_bound_interface);
6077 }
6078 new_kernel_policy->cond_bound_interface = cond_bound_interface;
6079 }
6080 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6081 new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6082 }
6083 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6084 new_kernel_policy->cond_protocol = cond_protocol;
6085 }
6086 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6087 memcpy(&new_kernel_policy->cond_local_start, cond_local_start, cond_local_start->sa.sa_len);
6088 }
6089 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6090 memcpy(&new_kernel_policy->cond_local_end, cond_local_end, cond_local_end->sa.sa_len);
6091 }
6092 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6093 new_kernel_policy->cond_local_prefix = cond_local_prefix;
6094 }
6095 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6096 memcpy(&new_kernel_policy->cond_remote_start, cond_remote_start, cond_remote_start->sa.sa_len);
6097 }
6098 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6099 memcpy(&new_kernel_policy->cond_remote_end, cond_remote_end, cond_remote_end->sa.sa_len);
6100 }
6101 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6102 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
6103 }
6104 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
6105 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
6106 }
6107 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
6108 new_kernel_policy->cond_scheme_port = cond_scheme_port;
6109 }
6110
6111 new_kernel_policy->result = result;
6112 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
6113
6114 if (necp_debug) {
6115 NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
6116 }
6117 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
6118
6119 return new_kernel_policy ? new_kernel_policy->id : 0;
6120 }
6121
6122 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)6123 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
6124 {
6125 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6126 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6127
6128 if (policy_id == 0) {
6129 return NULL;
6130 }
6131
6132 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
6133 if (kernel_policy->id == policy_id) {
6134 return kernel_policy;
6135 }
6136 }
6137
6138 return NULL;
6139 }
6140
6141 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)6142 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
6143 {
6144 struct necp_kernel_ip_output_policy *policy = NULL;
6145
6146 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6147
6148 policy = necp_kernel_ip_output_policy_find(policy_id);
6149 if (policy) {
6150 LIST_REMOVE(policy, chain);
6151
6152 if (policy->cond_bound_interface) {
6153 ifnet_release(policy->cond_bound_interface);
6154 policy->cond_bound_interface = NULL;
6155 }
6156
6157 zfree(necp_ip_policy_zone, policy);
6158 return TRUE;
6159 }
6160
6161 return FALSE;
6162 }
6163
6164 static void
necp_kernel_ip_output_policies_dump_all(void)6165 necp_kernel_ip_output_policies_dump_all(void)
6166 {
6167 if (necp_debug) {
6168 struct necp_kernel_ip_output_policy *policy = NULL;
6169 int policy_i;
6170 int id_i;
6171 char result_string[MAX_RESULT_STRING_LEN];
6172 char proc_name_string[MAXCOMLEN + 1];
6173 memset(result_string, 0, MAX_RESULT_STRING_LEN);
6174 memset(proc_name_string, 0, MAXCOMLEN + 1);
6175
6176 NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
6177 NECPLOG0(LOG_DEBUG, "-----------\n");
6178 for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
6179 NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
6180 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++) {
6181 policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
6182 proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
6183 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));
6184 }
6185 NECPLOG0(LOG_DEBUG, "-----------\n");
6186 }
6187 }
6188 }
6189
6190 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)6191 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
6192 {
6193 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6194 if (upper_policy->session_order != lower_policy->session_order) {
6195 // A skip cannot override a policy of a different session
6196 return FALSE;
6197 } else {
6198 if (upper_policy->result_parameter.skip_policy_order == 0 ||
6199 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
6200 // This policy is beyond the skip
6201 return FALSE;
6202 } else {
6203 // This policy is inside the skip
6204 return TRUE;
6205 }
6206 }
6207 }
6208
6209 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
6210 return TRUE;
6211 }
6212
6213 static bool
necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy * policy,struct necp_kernel_ip_output_policy ** policy_array,int valid_indices)6214 necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy *policy, struct necp_kernel_ip_output_policy **policy_array, int valid_indices)
6215 {
6216 bool can_skip = FALSE;
6217 u_int32_t highest_skip_session_order = 0;
6218 u_int32_t highest_skip_order = 0;
6219 int i;
6220 for (i = 0; i < valid_indices; i++) {
6221 struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
6222
6223 // For policies in a skip window, we can't mark conflicting policies as unnecessary
6224 if (can_skip) {
6225 if (highest_skip_session_order != compared_policy->session_order ||
6226 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
6227 // If we've moved on to the next session, or passed the skip window
6228 highest_skip_session_order = 0;
6229 highest_skip_order = 0;
6230 can_skip = FALSE;
6231 } else {
6232 // If this policy is also a skip, in can increase the skip window
6233 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6234 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
6235 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6236 }
6237 }
6238 continue;
6239 }
6240 }
6241
6242 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6243 // This policy is a skip. Set the skip window accordingly
6244 can_skip = TRUE;
6245 highest_skip_session_order = compared_policy->session_order;
6246 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6247 }
6248
6249 // The result of the compared policy must be able to block out this policy result
6250 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
6251 continue;
6252 }
6253
6254 // If new policy matches All Interfaces, compared policy must also
6255 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
6256 continue;
6257 }
6258
6259 // If new policy matches Local Networks, compared policy must also
6260 if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
6261 continue;
6262 }
6263
6264 // Default makes lower policies unecessary always
6265 if (compared_policy->condition_mask == 0) {
6266 return TRUE;
6267 }
6268
6269 // Compared must be more general than policy, and include only conditions within policy
6270 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
6271 continue;
6272 }
6273
6274 // Negative conditions must match for the overlapping conditions
6275 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
6276 continue;
6277 }
6278
6279 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
6280 compared_policy->cond_policy_id != policy->cond_policy_id) {
6281 continue;
6282 }
6283
6284 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
6285 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
6286 continue;
6287 }
6288
6289 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
6290 compared_policy->cond_protocol != policy->cond_protocol) {
6291 continue;
6292 }
6293
6294 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6295 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6296 if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&policy->cond_local_end, (struct sockaddr *)&compared_policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_end)) {
6297 continue;
6298 }
6299 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6300 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
6301 !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_start, compared_policy->cond_local_prefix)) {
6302 continue;
6303 }
6304 }
6305 }
6306
6307 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6308 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6309 if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&policy->cond_remote_end, (struct sockaddr *)&compared_policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_end)) {
6310 continue;
6311 }
6312 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6313 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
6314 !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_start, compared_policy->cond_remote_prefix)) {
6315 continue;
6316 }
6317 }
6318 }
6319
6320 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
6321 compared_policy->cond_scheme_port != policy->cond_scheme_port) {
6322 continue;
6323 }
6324
6325 return TRUE;
6326 }
6327
6328 return FALSE;
6329 }
6330
6331 static bool
necp_kernel_ip_output_policies_reprocess(void)6332 necp_kernel_ip_output_policies_reprocess(void)
6333 {
6334 int i;
6335 int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
6336 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6337
6338 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6339
6340 // Reset mask to 0
6341 necp_kernel_ip_output_policies_condition_mask = 0;
6342 necp_kernel_ip_output_policies_count = 0;
6343 necp_kernel_ip_output_policies_non_id_count = 0;
6344
6345 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6346 if (necp_kernel_ip_output_policies_map[i] != NULL) {
6347 kfree_type(struct necp_kernel_ip_output_policy *,
6348 necp_kernel_ip_output_policies_map_counts[i] + 1,
6349 necp_kernel_ip_output_policies_map[i]);
6350 necp_kernel_ip_output_policies_map[i] = NULL;
6351 }
6352
6353 // Init counts
6354 necp_kernel_ip_output_policies_map_counts[i] = 0;
6355 }
6356
6357 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6358 // Update mask
6359 necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
6360 necp_kernel_ip_output_policies_count++;
6361
6362 /* Update bucket counts:
6363 * Non-id and SKIP policies will be added to all buckets
6364 * Add local networks policy to all buckets for incoming IP
6365 */
6366 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6367 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6368 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6369 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6370 necp_kernel_ip_output_policies_map_counts[i]++;
6371 }
6372 }
6373 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
6374 necp_kernel_ip_output_policies_non_id_count++;
6375 } else {
6376 necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
6377 }
6378 }
6379
6380 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6381 if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
6382 // Allocate a NULL-terminated array of policy pointers for each bucket
6383 necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
6384 necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
6385 if (necp_kernel_ip_output_policies_map[i] == NULL) {
6386 goto fail;
6387 }
6388 }
6389 bucket_current_free_index[i] = 0;
6390 }
6391
6392 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6393 // Insert pointers into map
6394 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6395 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6396 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6397 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6398 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])) {
6399 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
6400 bucket_current_free_index[i]++;
6401 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
6402 }
6403 }
6404 } else {
6405 i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
6406 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])) {
6407 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
6408 bucket_current_free_index[i]++;
6409 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
6410 }
6411 }
6412 }
6413 necp_kernel_ip_output_policies_dump_all();
6414 return TRUE;
6415
6416 fail:
6417 // Free memory, reset mask to 0
6418 necp_kernel_ip_output_policies_condition_mask = 0;
6419 necp_kernel_ip_output_policies_count = 0;
6420 necp_kernel_ip_output_policies_non_id_count = 0;
6421 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6422 if (necp_kernel_ip_output_policies_map[i] != NULL) {
6423 kfree_type(struct necp_kernel_ip_output_policy *,
6424 necp_kernel_ip_output_policies_map_counts[i] + 1,
6425 necp_kernel_ip_output_policies_map[i]);
6426 necp_kernel_ip_output_policies_map[i] = NULL;
6427 }
6428 }
6429 return FALSE;
6430 }
6431
6432 // Outbound Policy Matching
6433 // ---------------------
6434 struct substring {
6435 char *string;
6436 size_t length;
6437 };
6438
6439 static struct substring
necp_trim_dots_and_stars(char * string,size_t length)6440 necp_trim_dots_and_stars(char *string, size_t length)
6441 {
6442 struct substring sub;
6443 sub.string = string;
6444 sub.length = string ? length : 0;
6445
6446 while (sub.length && (sub.string[0] == '.' || sub.string[0] == '*')) {
6447 sub.string++;
6448 sub.length--;
6449 }
6450
6451 while (sub.length && (sub.string[sub.length - 1] == '.' || sub.string[sub.length - 1] == '*')) {
6452 sub.length--;
6453 }
6454
6455 return sub;
6456 }
6457
6458 static char *
necp_create_trimmed_domain(char * string,size_t length)6459 necp_create_trimmed_domain(char *string, size_t length)
6460 {
6461 char *trimmed_domain = NULL;
6462 struct substring sub = necp_trim_dots_and_stars(string, length);
6463
6464 trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
6465 if (trimmed_domain == NULL) {
6466 return NULL;
6467 }
6468
6469 memcpy(trimmed_domain, sub.string, sub.length);
6470 trimmed_domain[sub.length] = 0;
6471
6472 return trimmed_domain;
6473 }
6474
6475 static inline int
necp_count_dots(char * string,size_t length)6476 necp_count_dots(char *string, size_t length)
6477 {
6478 int dot_count = 0;
6479 size_t i = 0;
6480
6481 for (i = 0; i < length; i++) {
6482 if (string[i] == '.') {
6483 dot_count++;
6484 }
6485 }
6486
6487 return dot_count;
6488 }
6489
6490 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)6491 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
6492 {
6493 if (parent.length <= suffix.length) {
6494 return FALSE;
6495 }
6496
6497 size_t length_difference = (parent.length - suffix.length);
6498
6499 if (require_dot_before_suffix) {
6500 if (((char *)(parent.string + length_difference - 1))[0] != '.') {
6501 return FALSE;
6502 }
6503 }
6504
6505 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
6506 return strncasecmp(parent.string + length_difference, suffix.string, suffix.length) == 0;
6507 }
6508
6509 static bool
necp_hostname_matches_domain(struct substring hostname_substring,u_int8_t hostname_dot_count,char * domain,u_int8_t domain_dot_count)6510 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain, u_int8_t domain_dot_count)
6511 {
6512 if (hostname_substring.string == NULL || domain == NULL) {
6513 return hostname_substring.string == domain;
6514 }
6515
6516 struct substring domain_substring;
6517 domain_substring.string = domain;
6518 domain_substring.length = strlen(domain);
6519
6520 if (hostname_dot_count == domain_dot_count) {
6521 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
6522 if (hostname_substring.length == domain_substring.length &&
6523 strncasecmp(hostname_substring.string, domain_substring.string, hostname_substring.length) == 0) {
6524 return TRUE;
6525 }
6526 } else if (domain_dot_count < hostname_dot_count) {
6527 if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
6528 return TRUE;
6529 }
6530 }
6531
6532 return FALSE;
6533 }
6534
6535 bool
net_domain_contains_hostname(char * hostname_string,char * domain_string)6536 net_domain_contains_hostname(char *hostname_string, char *domain_string)
6537 {
6538 if (hostname_string == NULL ||
6539 domain_string == NULL) {
6540 return false;
6541 }
6542
6543 struct substring hostname_substring;
6544 hostname_substring.string = hostname_string;
6545 hostname_substring.length = strlen(hostname_string);
6546
6547 return necp_hostname_matches_domain(hostname_substring,
6548 necp_count_dots(hostname_string, hostname_substring.length),
6549 domain_string,
6550 necp_count_dots(domain_string, strlen(domain_string)));
6551 }
6552
6553 #define NECP_MAX_STRING_LEN 1024
6554
6555 static char *
necp_copy_string(char * string,size_t length)6556 necp_copy_string(char *string, size_t length)
6557 {
6558 char *copied_string = NULL;
6559
6560 if (length > NECP_MAX_STRING_LEN) {
6561 return NULL;
6562 }
6563
6564 copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
6565 if (copied_string == NULL) {
6566 return NULL;
6567 }
6568
6569 memcpy(copied_string, string, length);
6570 copied_string[length] = 0;
6571
6572 return copied_string;
6573 }
6574
6575 static u_int32_t
necp_get_primary_direct_interface_index(void)6576 necp_get_primary_direct_interface_index(void)
6577 {
6578 u_int32_t interface_index = IFSCOPE_NONE;
6579
6580 ifnet_head_lock_shared();
6581 struct ifnet *ordered_interface = NULL;
6582 TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
6583 const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
6584 if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
6585 functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
6586 // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
6587 interface_index = ordered_interface->if_index;
6588 break;
6589 }
6590 }
6591 ifnet_head_done();
6592
6593 return interface_index;
6594 }
6595
6596 static inline bool
necp_task_has_match_entitlement(task_t task)6597 necp_task_has_match_entitlement(task_t task)
6598 {
6599 return task != NULL &&
6600 (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
6601 IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
6602 }
6603
6604 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)6605 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
6606 {
6607 coalition_t coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
6608
6609 if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
6610 // No parent, nothing to do
6611 return;
6612 }
6613
6614 task_t lead_task = coalition_get_leader(coal);
6615 if (lead_task != NULL) {
6616 info->is_entitled = necp_task_has_match_entitlement(lead_task);
6617 task_deallocate(lead_task);
6618 }
6619 }
6620
6621 // Some processes, due to particular entitlements, require using an NECP client to
6622 // access networking. Returns true if the result should be a Drop.
6623 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)6624 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
6625 {
6626 if (necp_is_platform_binary(proc)) {
6627 // This check is currently for the "on-demand-install-capable"
6628 // entitlement, which by definition cannot be a built-in platform
6629 // binary.
6630 return false;
6631 }
6632
6633 task_t task = proc_task(proc ? proc : current_proc());
6634
6635 if (!info->has_client &&
6636 task != NULL &&
6637 IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
6638 // Drop connections that don't use NECP clients and have the
6639 // com.apple.developer.on-demand-install-capable entitlement.
6640 // This effectively restricts those processes to only using
6641 // an NECP-aware path for networking.
6642 return true;
6643 } else {
6644 return false;
6645 }
6646 }
6647
6648 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)6649 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
6650 {
6651 if (!necp_restrict_multicast || proc == NULL) {
6652 return false;
6653 }
6654
6655 // Check for multicast/broadcast here
6656 if (info->remote_addr.sa.sa_family == AF_INET) {
6657 if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
6658 info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
6659 return false;
6660 }
6661 } else if (info->remote_addr.sa.sa_family == AF_INET6) {
6662 if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
6663 return false;
6664 }
6665 } else {
6666 // Not IPv4/IPv6
6667 return false;
6668 }
6669
6670 if (necp_is_platform_binary(proc)) {
6671 return false;
6672 }
6673
6674 const uint32_t platform = proc_platform(proc);
6675 const uint32_t sdk = proc_sdk(proc);
6676
6677 // Enforce for iOS, linked on or after version 14
6678 // If the caller set `check_minor_version`, only enforce starting at 14.5
6679 if ((platform != PLATFORM_IOS ||
6680 sdk == 0 ||
6681 (sdk >> 16) < 14 ||
6682 (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
6683 return false;
6684 }
6685
6686 // Allow entitled processes to use multicast
6687 task_t task = proc_task(proc);
6688 if (task != NULL &&
6689 IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
6690 return false;
6691 }
6692
6693 const uint32_t min_sdk = proc_min_sdk(proc);
6694 NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
6695
6696 return true;
6697 }
6698
6699 #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)
6700 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,char * domain,pid_t pid,int32_t pid_version,uid_t 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)6701 necp_application_fillout_info_locked(task_t task, uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account, char *domain, pid_t pid, int32_t pid_version, uid_t 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)
6702 {
6703 memset(info, 0, sizeof(struct necp_socket_info));
6704
6705 info->pid = pid;
6706 info->pid_version = pid_version;
6707 info->uid = uid;
6708 info->protocol = protocol;
6709 info->bound_interface_index = bound_interface_index;
6710 info->traffic_class = traffic_class;
6711 info->has_client = has_client;
6712 info->has_system_signed_result = has_system_signed_result;
6713 info->drop_order = drop_order;
6714 info->client_flags = client_flags;
6715 info->is_loopback = is_loopback;
6716 info->is_delegated = is_delegated;
6717
6718 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
6719 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
6720 if (existing_mapping) {
6721 info->application_id = existing_mapping->id;
6722 }
6723 }
6724
6725 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
6726 if (uuid_compare(application_uuid, real_application_uuid) == 0) {
6727 info->real_application_id = info->application_id;
6728 } else {
6729 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
6730 if (existing_mapping) {
6731 info->real_application_id = existing_mapping->id;
6732 }
6733 }
6734 }
6735
6736 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
6737 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
6738 if (existing_mapping != NULL) {
6739 info->real_application_id = info->application_id;
6740 info->application_id = existing_mapping->id;
6741 info->used_responsible_pid = true;
6742 }
6743 }
6744
6745 if (info->used_responsible_pid) {
6746 proc = responsible_proc;
6747 }
6748
6749 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
6750 info->is_entitled = necp_task_has_match_entitlement(task);
6751 if (!info->is_entitled) {
6752 // Task does not have entitlement, check the parent task
6753 necp_get_parent_is_entitled(task, info);
6754 }
6755 }
6756
6757 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY && proc != NULL) {
6758 info->is_platform_binary = necp_is_platform_binary(proc) ? true : false;
6759 }
6760
6761 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
6762 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
6763 }
6764
6765 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
6766 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
6767 if (existing_mapping) {
6768 info->account_id = existing_mapping->id;
6769 }
6770 }
6771
6772 if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
6773 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
6774 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
6775 info->domain = domain;
6776 }
6777
6778 if ((necp_data_tracing_level && necp_data_tracing_port) ||
6779 necp_restrict_multicast ||
6780 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
6781 if (local_addr && local_addr->sa.sa_len > 0) {
6782 memcpy(&info->local_addr, local_addr, local_addr->sa.sa_len);
6783 if (local_port != 0) {
6784 info->local_addr.sin6.sin6_port = local_port;
6785 }
6786 } else {
6787 if (remote_addr && remote_addr->sa.sa_len > 0) {
6788 info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
6789 info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
6790 } else {
6791 info->local_addr.sin6.sin6_family = AF_INET6;
6792 info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
6793 }
6794 if (local_port != 0) {
6795 info->local_addr.sin6.sin6_port = local_port;
6796 }
6797 }
6798 if (remote_addr && remote_addr->sa.sa_len > 0) {
6799 memcpy(&info->remote_addr, remote_addr, remote_addr->sa.sa_len);
6800 if (remote_port != 0) {
6801 info->remote_addr.sin6.sin6_port = remote_port;
6802 }
6803 } else if (remote_port != 0) {
6804 info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
6805 info->remote_addr.sin6.sin6_family = AF_INET6;
6806 info->remote_addr.sin6.sin6_port = remote_port;
6807 }
6808 }
6809
6810 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
6811 info->scheme_port = scheme_port;
6812 }
6813 }
6814
6815 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)6816 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
6817 {
6818 struct kev_netpolicy_ifdenied ev_ifdenied;
6819
6820 bzero(&ev_ifdenied, sizeof(ev_ifdenied));
6821
6822 ev_ifdenied.ev_data.epid = pid;
6823 uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
6824 ev_ifdenied.ev_if_functional_type = if_functional_type;
6825
6826 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
6827 }
6828
6829 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)6830 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
6831 {
6832 struct kev_netpolicy_netdenied ev_netdenied = {};
6833
6834 bzero(&ev_netdenied, sizeof(ev_netdenied));
6835
6836 ev_netdenied.ev_data.epid = pid;
6837 uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
6838 ev_netdenied.ev_network_type = network_type;
6839
6840 netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
6841 }
6842
6843 extern char *proc_name_address(void *p);
6844
6845 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
6846 if (!has_checked_delegation_entitlement) { \
6847 has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
6848 has_checked_delegation_entitlement = TRUE; \
6849 } \
6850 if (!has_delegation_entitlement) { \
6851 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
6852 proc_name_address(_p), proc_pid(_p), _d); \
6853 break; \
6854 }
6855
6856 int
necp_application_find_policy_match_internal(proc_t proc,u_int8_t * 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)6857 necp_application_find_policy_match_internal(proc_t proc,
6858 u_int8_t *parameters,
6859 u_int32_t parameters_size,
6860 struct necp_aggregate_result *returned_result,
6861 u_int32_t *flags,
6862 u_int32_t *reason,
6863 u_int required_interface_index,
6864 const union necp_sockaddr_union *override_local_addr,
6865 const union necp_sockaddr_union *override_remote_addr,
6866 struct necp_client_endpoint *returned_v4_gateway,
6867 struct necp_client_endpoint *returned_v6_gateway,
6868 struct rtentry **returned_route, bool ignore_address,
6869 bool has_client,
6870 uuid_t *returned_override_euuid)
6871 {
6872 int error = 0;
6873 size_t offset = 0;
6874
6875 struct necp_kernel_socket_policy *matched_policy = NULL;
6876 struct necp_socket_info info;
6877 necp_kernel_policy_filter filter_control_unit = 0;
6878 necp_kernel_policy_result service_action = 0;
6879 necp_kernel_policy_service service = { 0, 0 };
6880
6881 u_int16_t protocol = 0;
6882 u_int32_t bound_interface_index = required_interface_index;
6883 u_int32_t traffic_class = 0;
6884 u_int32_t client_flags = 0;
6885 u_int16_t scheme_port = 0;
6886 union necp_sockaddr_union local_addr;
6887 union necp_sockaddr_union remote_addr;
6888 bool no_remote_addr = FALSE;
6889 u_int8_t remote_family = 0;
6890 bool no_local_addr = FALSE;
6891 u_int16_t local_port = 0;
6892 u_int16_t remote_port = 0;
6893 u_int32_t remote_endpoint_type = 0;
6894 bool remote_address_is_empty = false;
6895 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
6896 bool is_delegated = false;
6897
6898 if (override_local_addr) {
6899 memcpy(&local_addr, override_local_addr, sizeof(local_addr));
6900 } else {
6901 memset(&local_addr, 0, sizeof(local_addr));
6902 }
6903 if (override_remote_addr) {
6904 memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
6905 } else {
6906 memset(&remote_addr, 0, sizeof(remote_addr));
6907 }
6908
6909 // Initialize UID, PID, and UUIDs to the current process
6910 uid_t uid = 0;
6911 kauth_cred_t cred = kauth_cred_proc_ref(proc);
6912 if (cred != NULL) {
6913 uid = kauth_cred_getuid(cred);
6914 }
6915 task_t task = proc_task(proc);
6916 pid_t pid = proc_pid(proc);
6917 int32_t pid_version = proc_pidversion(proc);
6918 uuid_t application_uuid;
6919 uuid_clear(application_uuid);
6920 uuid_t real_application_uuid;
6921 uuid_clear(real_application_uuid);
6922 proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
6923 uuid_copy(application_uuid, real_application_uuid);
6924 uuid_t responsible_application_uuid;
6925 uuid_clear(responsible_application_uuid);
6926
6927 char *domain = NULL;
6928 char *account = NULL;
6929
6930 #define NECP_MAX_REQUIRED_AGENTS 16
6931 u_int32_t num_required_agent_types = 0;
6932 struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
6933 memset(&required_agent_types, 0, sizeof(required_agent_types));
6934
6935 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
6936 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
6937 memset(&netagent_ids, 0, sizeof(netagent_ids));
6938 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
6939 int netagent_cursor;
6940
6941 bool has_checked_delegation_entitlement = false;
6942 bool has_delegation_entitlement = false;
6943 bool has_system_signed_result = false;
6944
6945 proc_t responsible_proc = PROC_NULL;
6946 proc_t effective_proc = proc;
6947 bool release_eproc = false;
6948 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
6949
6950 u_int32_t flow_divert_aggregate_unit = 0;
6951
6952 if (returned_result == NULL) {
6953 if (cred != NULL) {
6954 kauth_cred_unref(&cred);
6955 }
6956 return EINVAL;
6957 }
6958
6959 if (returned_v4_gateway != NULL) {
6960 memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
6961 }
6962
6963 if (returned_v6_gateway != NULL) {
6964 memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
6965 }
6966
6967 if (returned_override_euuid != NULL) {
6968 uuid_clear(*returned_override_euuid);
6969 }
6970
6971 memset(returned_result, 0, sizeof(struct necp_aggregate_result));
6972
6973 u_int32_t drop_order = necp_process_drop_order(cred);
6974
6975 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
6976
6977 lck_rw_lock_shared(&necp_kernel_policy_lock);
6978 if (necp_kernel_application_policies_count == 0) {
6979 if (necp_drop_all_order > 0 || drop_order > 0) {
6980 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
6981 lck_rw_done(&necp_kernel_policy_lock);
6982 if (cred != NULL) {
6983 kauth_cred_unref(&cred);
6984 }
6985 return 0;
6986 }
6987 }
6988 lck_rw_done(&necp_kernel_policy_lock);
6989
6990 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
6991 u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
6992 u_int32_t length = necp_buffer_get_tlv_length(parameters, offset);
6993
6994 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
6995 // If the length is larger than what can fit in the remaining parameters size, bail
6996 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
6997 break;
6998 }
6999
7000 if (length > 0) {
7001 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
7002 if (value != NULL) {
7003 switch (type) {
7004 case NECP_CLIENT_PARAMETER_APPLICATION: {
7005 if (length >= sizeof(uuid_t)) {
7006 if (uuid_compare(application_uuid, value) == 0) {
7007 // No delegation
7008 break;
7009 }
7010
7011 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
7012
7013 is_delegated = true;
7014 uuid_copy(application_uuid, value);
7015 }
7016 break;
7017 }
7018 case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
7019 if (length >= sizeof(uuid_t)) {
7020 if (uuid_compare(real_application_uuid, value) == 0) {
7021 // No delegation
7022 break;
7023 }
7024
7025 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
7026
7027 is_delegated = true;
7028 uuid_copy(real_application_uuid, value);
7029 }
7030 break;
7031 }
7032 case NECP_CLIENT_PARAMETER_PID: {
7033 if (length >= sizeof(pid_t)) {
7034 if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
7035 // No delegation
7036 break;
7037 }
7038
7039 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
7040
7041 is_delegated = true;
7042 memcpy(&pid, value, sizeof(pid_t));
7043 }
7044 break;
7045 }
7046 case NECP_CLIENT_PARAMETER_UID: {
7047 if (length >= sizeof(uid_t)) {
7048 if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
7049 // No delegation
7050 break;
7051 }
7052
7053 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
7054
7055 is_delegated = true;
7056 memcpy(&uid, value, sizeof(uid_t));
7057 }
7058 break;
7059 }
7060 case NECP_CLIENT_PARAMETER_DOMAIN: {
7061 domain = (char *)value;
7062 domain[length - 1] = 0;
7063 break;
7064 }
7065 case NECP_CLIENT_PARAMETER_ACCOUNT: {
7066 account = (char *)value;
7067 account[length - 1] = 0;
7068 break;
7069 }
7070 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
7071 if (length >= sizeof(u_int32_t)) {
7072 memcpy(&traffic_class, value, sizeof(u_int32_t));
7073 }
7074 break;
7075 }
7076 case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
7077 if (length >= sizeof(u_int16_t)) {
7078 memcpy(&protocol, value, sizeof(u_int16_t));
7079 } else if (length >= sizeof(u_int8_t)) {
7080 memcpy(&protocol, value, sizeof(u_int8_t));
7081 }
7082 break;
7083 }
7084 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
7085 if (length <= IFXNAMSIZ && length > 0) {
7086 ifnet_t bound_interface = NULL;
7087 char interface_name[IFXNAMSIZ];
7088 memcpy(interface_name, value, length);
7089 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
7090 if (ifnet_find_by_name(interface_name, &bound_interface) == 0) {
7091 bound_interface_index = bound_interface->if_index;
7092 ifnet_release(bound_interface);
7093 }
7094 }
7095 break;
7096 }
7097 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
7098 if (ignore_address || override_local_addr) {
7099 break;
7100 }
7101
7102 if (length >= sizeof(struct necp_policy_condition_addr)) {
7103 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7104 if (necp_address_is_valid(&address_struct->address.sa)) {
7105 memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
7106 }
7107 }
7108 break;
7109 }
7110 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
7111 if (ignore_address || override_remote_addr) {
7112 break;
7113 }
7114
7115 if (length >= sizeof(struct necp_policy_condition_addr)) {
7116 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7117 if (necp_address_is_valid(&address_struct->address.sa)) {
7118 memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
7119 }
7120 }
7121 break;
7122 }
7123 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
7124 if (ignore_address || override_local_addr) {
7125 break;
7126 }
7127
7128 if (length >= sizeof(struct necp_client_endpoint)) {
7129 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7130 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
7131 endpoint->u.endpoint.endpoint_port != 0) {
7132 // Save port
7133 local_port = endpoint->u.endpoint.endpoint_port;
7134 }
7135 }
7136 break;
7137 }
7138 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
7139 if (ignore_address || override_remote_addr) {
7140 break;
7141 }
7142
7143 if (length >= sizeof(struct necp_client_endpoint)) {
7144 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7145 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
7146 remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
7147 if (endpoint->u.endpoint.endpoint_port != 0) {
7148 // Save port
7149 remote_port = endpoint->u.endpoint.endpoint_port;
7150 }
7151 } else if (necp_addr_is_empty(&endpoint->u.sa)) {
7152 remote_address_is_empty = true;
7153 }
7154 }
7155 break;
7156 }
7157 case NECP_CLIENT_PARAMETER_FLAGS: {
7158 if (length >= sizeof(client_flags)) {
7159 memcpy(&client_flags, value, sizeof(client_flags));
7160 }
7161 break;
7162 }
7163 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
7164 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
7165 if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
7166 break;
7167 }
7168 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
7169 memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
7170 num_required_agent_types++;
7171 }
7172 break;
7173 }
7174 case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
7175 if (length >= sizeof(scheme_port)) {
7176 memcpy(&scheme_port, value, sizeof(scheme_port));
7177 }
7178 break;
7179 }
7180 case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
7181 has_system_signed_result = true;
7182 struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
7183 if (length >= sizeof(struct necp_client_validatable)) {
7184 // Check for system-signed sign_type values
7185 if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
7186 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
7187 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
7188 has_system_signed_result = true;
7189 }
7190 }
7191 break;
7192 }
7193 default: {
7194 break;
7195 }
7196 }
7197 }
7198 }
7199
7200 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
7201 }
7202
7203 // Check for loopback exception
7204 if (necp_pass_loopback > 0 && necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
7205 bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
7206 } else if (bound_interface_index != IFSCOPE_NONE) {
7207 // Check for inter-process exception
7208 struct sockaddr *dst = SA(&remote_addr.sa);
7209 if (dst->sa_family == AF_INET6) {
7210 struct in6_addr *addrv6 = &(((struct sockaddr_in6 *)(void *)dst)->sin6_addr);
7211 if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
7212 ifnet_head_lock_shared();
7213 ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
7214 if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
7215 bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
7216 }
7217 ifnet_head_done();
7218 }
7219 }
7220 }
7221
7222 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
7223 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7224 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
7225 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
7226 returned_result->routed_interface_index = lo_ifp->if_index;
7227 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7228 } else {
7229 returned_result->routed_interface_index = bound_interface_index;
7230 }
7231 if (cred != NULL) {
7232 kauth_cred_unref(&cred);
7233 }
7234 return 0;
7235 }
7236
7237 if (drop_order != 0) {
7238 if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
7239 client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
7240 ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
7241 // Allow listeners, inbound connections without remote addresses, and
7242 // application service connections to bypass the unentitled drop order,
7243 // to allow them to connect to application services (not directly over
7244 // physical networking interfaces)
7245 drop_order = 0;
7246 }
7247 }
7248
7249 if (proc_pid(effective_proc) != pid) {
7250 proc_t found_proc = proc_find(pid);
7251 if (found_proc != PROC_NULL) {
7252 effective_proc = found_proc;
7253 pid_version = proc_pidversion(effective_proc);
7254 release_eproc = true;
7255 }
7256 }
7257 #if defined(XNU_TARGET_OS_OSX)
7258 if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
7259 responsible_proc = proc_find(effective_proc->p_responsible_pid);
7260 if (responsible_proc != PROC_NULL) {
7261 proc_getexecutableuuid(responsible_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
7262 }
7263 }
7264 #endif /* defined(XNU_TARGET_OS_OSX) */
7265
7266 // Lock
7267 lck_rw_lock_shared(&necp_kernel_policy_lock);
7268
7269 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
7270 size_t route_rule_id_array_count = 0;
7271 necp_application_fillout_info_locked(task, application_uuid, real_application_uuid, responsible_application_uuid, account, domain, pid, pid_version, 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);
7272
7273 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid);
7274 NECP_DATA_TRACE_LOG_SOCKET(debug, "APPLICATION", "START", 0, 0);
7275
7276 matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map, &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, netagent_use_flags, NECP_MAX_NETAGENTS, required_agent_types, num_required_agent_types, info.used_responsible_pid ? responsible_proc : effective_proc, 0, NULL, NULL, &drop_dest_policy_result, &drop_all_bypass, &flow_divert_aggregate_unit, NULL, debug);
7277
7278 // Check for loopback exception again after the policy match
7279 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
7280 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
7281 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
7282 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
7283 returned_result->filter_control_unit = 0;
7284 } else {
7285 returned_result->filter_control_unit = filter_control_unit;
7286 }
7287
7288 if (flow_divert_aggregate_unit > 0) {
7289 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
7290 }
7291
7292 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7293 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
7294 returned_result->routed_interface_index = lo_ifp->if_index;
7295 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7296 error = 0;
7297 goto done;
7298 }
7299
7300 if (matched_policy) {
7301 returned_result->policy_id = matched_policy->id;
7302 returned_result->routing_result = matched_policy->result;
7303 memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
7304 if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
7305 uuid_copy(*returned_override_euuid, responsible_application_uuid);
7306 }
7307 } else {
7308 bool drop_all = false;
7309 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
7310 // Mark socket as a drop if drop_all is set
7311 drop_all = true;
7312 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
7313 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
7314 }
7315 }
7316 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
7317 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7318 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7319 NECP_DATA_TRACE_LOG_SOCKET(debug, "APPLICATION", "DROP <NO MATCH>", 0, 0);
7320 } else {
7321 returned_result->policy_id = 0;
7322 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
7323 }
7324 }
7325 if (necp_check_missing_client_drop(proc, &info) ||
7326 necp_check_restricted_multicast_drop(proc, &info, false)) {
7327 // Mark as drop
7328 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7329 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7330 NECP_DATA_TRACE_LOG_SOCKET(debug, "APPLICATION", "DROP <NO CLIENT / MULTICAST>", 0, 0);
7331 }
7332 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
7333 returned_result->filter_control_unit = 0;
7334 } else {
7335 returned_result->filter_control_unit = filter_control_unit;
7336 }
7337
7338 if (flow_divert_aggregate_unit > 0) {
7339 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
7340 }
7341
7342 returned_result->service_action = service_action;
7343
7344 // Fetch service registration
7345 if (service.identifier != 0) {
7346 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
7347 if (mapping != NULL) {
7348 struct necp_service_registration *service_registration = NULL;
7349 uuid_copy(returned_result->service_uuid, mapping->uuid);
7350 returned_result->service_data = service.data;
7351 if (service.identifier == NECP_NULL_SERVICE_ID) {
7352 // NULL service is always 'registered'
7353 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
7354 } else {
7355 LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
7356 if (service.identifier == service_registration->service_id) {
7357 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
7358 break;
7359 }
7360 }
7361 }
7362 }
7363 }
7364
7365 // Handle netagents
7366 size_t netagent_i = 0;
7367 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
7368 struct necp_uuid_id_mapping *mapping = NULL;
7369 u_int32_t netagent_id = netagent_ids[netagent_cursor];
7370 if (netagent_id == 0) {
7371 continue;
7372 }
7373 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
7374 if (mapping != NULL) {
7375 uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
7376 returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
7377 netagent_i++;
7378 }
7379
7380 // If the flags say to remove, clear the local copy
7381 if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
7382 netagent_ids[netagent_cursor] = 0;
7383 }
7384 }
7385
7386 // Do routing evaluation
7387 u_int output_bound_interface = bound_interface_index;
7388 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
7389 output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
7390 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
7391 output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
7392 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
7393 output_bound_interface = necp_get_primary_direct_interface_index();
7394 if (output_bound_interface == IFSCOPE_NONE) {
7395 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7396 } else {
7397 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
7398 returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
7399 }
7400 }
7401
7402 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
7403 returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
7404 // Trigger the event that we dropped due to a local network policy
7405 necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
7406 if (reason != NULL) {
7407 *reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
7408 }
7409 }
7410
7411 if (local_addr.sa.sa_len == 0 ||
7412 (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
7413 (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
7414 no_local_addr = TRUE;
7415 }
7416
7417 if (remote_addr.sa.sa_len == 0 ||
7418 (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
7419 (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
7420 no_remote_addr = TRUE;
7421 remote_family = remote_addr.sa.sa_family;
7422 }
7423
7424 returned_result->routed_interface_index = 0;
7425 struct rtentry *rt = NULL;
7426 if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
7427 // Treat the output bound interface as the routed interface for local address
7428 // validation later.
7429 returned_result->routed_interface_index = output_bound_interface;
7430 } else {
7431 if (no_remote_addr) {
7432 memset(&remote_addr, 0, sizeof(remote_addr));
7433 if (remote_family == AF_INET6) {
7434 // Reset address to ::
7435 remote_addr.sa.sa_family = AF_INET6;
7436 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
7437 } else {
7438 // Reset address to 0.0.0.0
7439 remote_addr.sa.sa_family = AF_INET;
7440 remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
7441 }
7442 }
7443
7444 rt = rtalloc1_scoped((struct sockaddr *)&remote_addr, 0, 0,
7445 output_bound_interface);
7446
7447 if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
7448 IS_INTF_CLAT46(rt->rt_ifp)) {
7449 rtfree(rt);
7450 rt = NULL;
7451 returned_result->routed_interface_index = 0;
7452 }
7453
7454 if (no_remote_addr && remote_family == AF_UNSPEC &&
7455 (rt == NULL || rt->rt_ifp == NULL)) {
7456 // Route lookup for default IPv4 failed, try IPv6
7457
7458 // Cleanup old route if necessary
7459 if (rt != NULL) {
7460 rtfree(rt);
7461 rt = NULL;
7462 }
7463
7464 // Reset address to ::
7465 memset(&remote_addr, 0, sizeof(remote_addr));
7466 remote_addr.sa.sa_family = AF_INET6;
7467 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
7468
7469 // Get route
7470 rt = rtalloc1_scoped((struct sockaddr *)&remote_addr, 0, 0,
7471 output_bound_interface);
7472 }
7473
7474 if (rt != NULL &&
7475 rt->rt_ifp != NULL) {
7476 returned_result->routed_interface_index = rt->rt_ifp->if_index;
7477 /*
7478 * For local addresses, we allow the interface scope to be
7479 * either the loopback interface or the interface hosting the
7480 * local address.
7481 */
7482 if (bound_interface_index != IFSCOPE_NONE &&
7483 rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
7484 (output_bound_interface == lo_ifp->if_index ||
7485 rt->rt_ifp->if_index == lo_ifp->if_index ||
7486 rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
7487 struct sockaddr_storage dst;
7488 unsigned int ifscope = bound_interface_index;
7489
7490 /*
7491 * Transform dst into the internal routing table form
7492 */
7493 (void) sa_copy((struct sockaddr *)&remote_addr,
7494 &dst, &ifscope);
7495
7496 if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
7497 rt_ifa_is_dst((struct sockaddr *)&dst, rt->rt_ifa)) {
7498 returned_result->routed_interface_index =
7499 bound_interface_index;
7500 }
7501 }
7502 }
7503 }
7504
7505 if (returned_result->routed_interface_index != 0 &&
7506 returned_result->routed_interface_index != lo_ifp->if_index && // Loopback can accept any local address
7507 !no_local_addr) {
7508 // Transform local_addr into the ifaddr form
7509 // IPv6 Scope IDs are always embedded in the ifaddr list
7510 struct sockaddr_storage local_address_sanitized;
7511 u_int ifscope = IFSCOPE_NONE;
7512 (void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
7513 SIN(&local_address_sanitized)->sin_port = 0;
7514 if (local_address_sanitized.ss_family == AF_INET6) {
7515 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
7516 SIN6(&local_address_sanitized)->sin6_scope_id = 0;
7517 }
7518 }
7519
7520 // Validate local address on routed interface
7521 struct ifaddr *ifa = ifa_ifwithaddr_scoped((struct sockaddr *)&local_address_sanitized, returned_result->routed_interface_index);
7522 if (ifa == NULL) {
7523 // Interface address not found, reject route
7524 returned_result->routed_interface_index = 0;
7525 if (rt != NULL) {
7526 rtfree(rt);
7527 rt = NULL;
7528 }
7529 } else {
7530 ifaddr_release(ifa);
7531 ifa = NULL;
7532 }
7533 }
7534
7535 if (flags != NULL) {
7536 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
7537 enum net_filter_event_subsystems filters = net_filter_event_get_state();
7538
7539 if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
7540 *flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
7541 }
7542 if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
7543 *flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
7544 }
7545 if (filters & NET_FILTER_EVENT_ALF) {
7546 *flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
7547 }
7548 if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
7549 *flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
7550 }
7551 #endif /* SKYWALK && defined(XNU_TARGET_OS_OSX) */
7552 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
7553 // Check for local/direct
7554 bool is_local = FALSE;
7555 if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
7556 is_local = TRUE;
7557 } else if (returned_result->routed_interface_index != 0 &&
7558 !no_remote_addr) {
7559 // Clean up the address before comparison with interface addresses
7560
7561 // Transform remote_addr into the ifaddr form
7562 // IPv6 Scope IDs are always embedded in the ifaddr list
7563 struct sockaddr_storage remote_address_sanitized;
7564 u_int ifscope = IFSCOPE_NONE;
7565 (void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
7566 SIN(&remote_address_sanitized)->sin_port = 0;
7567 if (remote_address_sanitized.ss_family == AF_INET6) {
7568 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
7569 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
7570 }
7571 }
7572
7573 // Check if remote address is an interface address
7574 struct ifaddr *ifa = ifa_ifwithaddr((struct sockaddr *)&remote_address_sanitized);
7575 if (ifa != NULL && ifa->ifa_ifp != NULL) {
7576 u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
7577 if (if_index_for_remote_addr == returned_result->routed_interface_index ||
7578 if_index_for_remote_addr == lo_ifp->if_index) {
7579 is_local = TRUE;
7580 }
7581 }
7582 if (ifa != NULL) {
7583 ifaddr_release(ifa);
7584 ifa = NULL;
7585 }
7586 }
7587
7588 if (is_local) {
7589 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7590 } else if (rt != NULL) {
7591 if (rt->rt_flags & RTF_GLOBAL) {
7592 *flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
7593 } else if (!(rt->rt_flags & RTF_GATEWAY) &&
7594 (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
7595 // Route is directly accessible
7596 *flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
7597 }
7598 }
7599
7600 if (rt != NULL &&
7601 rt->rt_ifp != NULL) {
7602 // Check probe status
7603 if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
7604 *flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
7605 }
7606
7607 if (rt->rt_ifp->if_type == IFT_CELLULAR) {
7608 struct if_cellular_status_v1 *ifsr;
7609
7610 ifnet_lock_shared(rt->rt_ifp);
7611 lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
7612
7613 if (rt->rt_ifp->if_link_status != NULL) {
7614 ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
7615
7616 if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
7617 if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
7618 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
7619 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
7620 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
7621 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
7622 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
7623 }
7624 }
7625 }
7626 lck_rw_done(&rt->rt_ifp->if_link_status_lock);
7627 ifnet_lock_done(rt->rt_ifp);
7628 }
7629
7630 // Check link quality
7631 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
7632 (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
7633 rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
7634 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
7635 }
7636
7637 // Check QoS marking (fastlane)
7638 for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
7639 if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
7640 *flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
7641 // If the route can use QoS markings, stop iterating route rules
7642 break;
7643 }
7644 }
7645
7646 if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
7647 *flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
7648 }
7649
7650 if (traffic_class == SO_TC_BK_SYS) {
7651 // Block BK_SYS traffic if interface is throttled
7652 u_int32_t throttle_level = 0;
7653 if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
7654 if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
7655 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7656 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
7657 }
7658 }
7659 }
7660 }
7661 }
7662
7663 if (returned_result->routed_interface_index != 0) {
7664 union necp_sockaddr_union default_address;
7665 struct rtentry *v4Route = NULL;
7666 struct rtentry *v6Route = NULL;
7667
7668 memset(&default_address, 0, sizeof(default_address));
7669
7670 // Reset address to 0.0.0.0
7671 default_address.sa.sa_family = AF_INET;
7672 default_address.sa.sa_len = sizeof(struct sockaddr_in);
7673 v4Route = rtalloc1_scoped((struct sockaddr *)&default_address, 0, 0,
7674 returned_result->routed_interface_index);
7675
7676 // Reset address to ::
7677 default_address.sa.sa_family = AF_INET6;
7678 default_address.sa.sa_len = sizeof(struct sockaddr_in6);
7679 v6Route = rtalloc1_scoped((struct sockaddr *)&default_address, 0, 0,
7680 returned_result->routed_interface_index);
7681
7682 if (v4Route != NULL) {
7683 if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
7684 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
7685 }
7686 if (returned_v4_gateway != NULL &&
7687 v4Route->rt_gateway != NULL &&
7688 v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
7689 memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
7690 memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
7691 }
7692 rtfree(v4Route);
7693 v4Route = NULL;
7694 }
7695
7696 if (v6Route != NULL) {
7697 if (v6Route->rt_ifp != NULL) {
7698 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
7699
7700 if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
7701 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
7702 }
7703 }
7704 if (returned_v6_gateway != NULL &&
7705 v6Route->rt_gateway != NULL &&
7706 v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
7707 memcpy(&returned_v6_gateway->u.sin6, v6Route->rt_gateway, sizeof(returned_v6_gateway->u.sin6));
7708 }
7709 rtfree(v6Route);
7710 v6Route = NULL;
7711 }
7712 }
7713 }
7714
7715 // Take two passes through the rule list: first for rules that don't match based on agents,
7716 // second for rules that match based on agents. Since rules can modify the agent list itself,
7717 // this makes the logic more deterministic. This allows a non-agent matching rule to remove
7718 // an agent before it is used for matching later.
7719 size_t route_rule_index = 0;
7720 bool second_pass = false;
7721 while (route_rule_index < route_rule_id_array_count) {
7722 bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
7723 if (rule_matches_agents != second_pass) {
7724 // Process rules that match based on agents only in the second pass
7725 route_rule_index++;
7726 if (route_rule_index == route_rule_id_array_count && !second_pass) {
7727 route_rule_index = 0;
7728 second_pass = true;
7729 }
7730 continue;
7731 }
7732
7733 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
7734 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);
7735 if (!route_is_allowed) {
7736 // If the route is blocked, treat the lookup as a drop
7737 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7738 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
7739
7740 if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
7741 if (reason != NULL) {
7742 if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
7743 *reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
7744 } else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
7745 *reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
7746 }
7747 }
7748 necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
7749 }
7750 // If the route gets denied, stop matching rules
7751 break;
7752 }
7753
7754 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
7755 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
7756 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index]);
7757 if (flow_divert_control_unit != 0) {
7758 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
7759 returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
7760 }
7761 }
7762
7763 // Check if there is a route rule that adds or removes an agent
7764 bool remove = false;
7765 u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
7766 if (netagent_id != 0) {
7767 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
7768 if (mapping != NULL) {
7769 bool agent_already_present = false;
7770 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
7771 if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
7772 // Found the agent already present
7773 agent_already_present = true;
7774 if (remove) {
7775 // Mark as remove if necessary
7776 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
7777 }
7778 } else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
7779 // Found open slot
7780 if (!agent_already_present) {
7781 uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
7782 if (remove) {
7783 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
7784 } else {
7785 returned_result->netagent_use_flags[netagent_cursor] = 0;
7786 }
7787 }
7788 break;
7789 }
7790 }
7791 }
7792
7793 // Update the local netagent_ids array for future evaluations
7794 if (remove) {
7795 // Check if the agent ID is in the array, and remove it
7796 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
7797 if (netagent_id == netagent_ids[netagent_cursor]) {
7798 netagent_ids[netagent_cursor] = 0;
7799 }
7800 }
7801 } else {
7802 // Check if the agent ID is not yet in the array, and add it
7803 bool found = false;
7804 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
7805 if (netagent_id == netagent_ids[netagent_cursor]) {
7806 found = true;
7807 break;
7808 }
7809 }
7810 if (!found) {
7811 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
7812 if (netagent_ids[netagent_cursor] == 0) {
7813 // Empty slot, add the agent
7814 netagent_ids[netagent_cursor] = netagent_id;
7815 break;
7816 }
7817 }
7818 }
7819 }
7820 }
7821
7822 route_rule_index++;
7823 if (route_rule_index == route_rule_id_array_count && !second_pass) {
7824 route_rule_index = 0;
7825 second_pass = true;
7826 }
7827 }
7828
7829 if (rt != NULL && rt->rt_ifp != NULL) {
7830 const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
7831 IFNET_IS_EXPENSIVE(rt->rt_ifp));
7832 const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
7833 IFNET_IS_CONSTRAINED(rt->rt_ifp));
7834 if (reason != NULL) {
7835 if (expensive_prohibited) {
7836 *reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
7837 } else if (constrained_prohibited) {
7838 *reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
7839 }
7840 }
7841 if (expensive_prohibited || constrained_prohibited) {
7842 // If the client flags prohibited a property of the interface, treat it as a drop
7843 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7844 memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
7845 }
7846 }
7847
7848 if (rt != NULL) {
7849 if (returned_route != NULL) {
7850 *returned_route = rt;
7851 } else {
7852 rtfree(rt);
7853 }
7854 rt = NULL;
7855 }
7856
7857 done:
7858 // Unlock
7859 lck_rw_done(&necp_kernel_policy_lock);
7860
7861 if (release_eproc && effective_proc != PROC_NULL) {
7862 proc_rele(effective_proc);
7863 }
7864 #if defined(XNU_TARGET_OS_OSX)
7865 if (responsible_proc != PROC_NULL) {
7866 proc_rele(responsible_proc);
7867 }
7868 #endif
7869
7870 if (cred != NULL) {
7871 kauth_cred_unref(&cred);
7872 }
7873
7874 return error;
7875 }
7876
7877 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr)7878 necp_is_route_local(union necp_sockaddr_union *remote_addr)
7879 {
7880 struct rtentry *rt = NULL;
7881 bool is_local = FALSE;
7882
7883 if (remote_addr == NULL) {
7884 return NULL;
7885 }
7886
7887 if (remote_addr->sa.sa_len == 0 ||
7888 (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
7889 (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
7890 return FALSE;
7891 }
7892
7893 // Lookup route regardless of the scoped interface to check if
7894 // remote address is in a local network.
7895 rt = rtalloc1_scoped((struct sockaddr *)remote_addr, 0, 0, 0);
7896
7897 if (rt == NULL) {
7898 goto done;
7899 }
7900 if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
7901 goto free_rt;
7902 }
7903 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt);
7904
7905 free_rt:
7906 rtfree(rt);
7907
7908 done:
7909 return is_local;
7910 }
7911
7912 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,pid_t pid,int32_t pid_version,uid_t 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 * 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,struct necp_socket_info * info,bool is_delegated)7913 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, pid_t pid, int32_t pid_version, uid_t 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 *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, struct necp_socket_info *info, bool is_delegated)
7914 {
7915 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
7916 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
7917 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
7918 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
7919 "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
7920 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
7921 if (bound_interface_index == cond_bound_interface_index) {
7922 // No match, matches forbidden interface
7923 return FALSE;
7924 }
7925 } else {
7926 if (bound_interface_index != cond_bound_interface_index) {
7927 // No match, does not match required interface
7928 return FALSE;
7929 }
7930 }
7931 } else {
7932 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
7933 if (bound_interface_index != 0) {
7934 // No match, requires a non-bound packet
7935 return FALSE;
7936 }
7937 }
7938 }
7939
7940 if (kernel_policy->condition_mask == 0) {
7941 return TRUE;
7942 }
7943
7944 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
7945 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
7946 "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
7947 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
7948 if (app_id == kernel_policy->cond_app_id) {
7949 // No match, matches forbidden application
7950 return FALSE;
7951 }
7952 } else {
7953 if (app_id != kernel_policy->cond_app_id) {
7954 // No match, does not match required application
7955 return FALSE;
7956 }
7957 }
7958
7959 // Check signing identifier only after APP ID matched
7960 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
7961 kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
7962 u_int8_t matched = necp_boolean_state_false;
7963 const char *signing_id = cs_identity_get(proc ? proc : current_proc());
7964 NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
7965 "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
7966 kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
7967 signing_id ? signing_id : "<n/a>");
7968 if (signing_id != NULL) {
7969 size_t signing_id_size = strlen(signing_id) + 1;
7970 if (memcmp(signing_id, kernel_policy->cond_signing_identifier, signing_id_size) == 0) {
7971 matched = necp_boolean_state_true;
7972 }
7973 }
7974
7975 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
7976 if (matched == necp_boolean_state_true) {
7977 return FALSE;
7978 }
7979 } else {
7980 if (matched != necp_boolean_state_true) {
7981 return FALSE;
7982 }
7983 }
7984 }
7985 }
7986
7987 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
7988 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
7989 "NECP_KERNEL_CONDITION_REAL_APP_ID",
7990 kernel_policy->cond_real_app_id, real_app_id);
7991 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
7992 if (real_app_id == kernel_policy->cond_real_app_id) {
7993 // No match, matches forbidden application
7994 return FALSE;
7995 }
7996 } else {
7997 if (real_app_id != kernel_policy->cond_real_app_id) {
7998 // No match, does not match required application
7999 return FALSE;
8000 }
8001 }
8002 }
8003
8004 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
8005 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
8006 if (!has_client) {
8007 return FALSE;
8008 }
8009 }
8010
8011 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
8012 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
8013 if (!is_entitled) {
8014 // Process is missing entitlement
8015 return FALSE;
8016 }
8017 }
8018
8019 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
8020 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_PLATFORM_BINARY", 0, is_platform_binary);
8021 if (is_platform_binary == 0) {
8022 // Process is not platform binary
8023 return FALSE;
8024 }
8025 }
8026
8027 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
8028 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
8029 if (has_signed_result == 0) {
8030 // Client did not have a system-signed result
8031 return FALSE;
8032 }
8033 }
8034
8035 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
8036 if (proc != NULL) {
8037 NECP_DATA_TRACE_LOG_CONDITION3(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
8038 kernel_policy->cond_sdk_version.platform,
8039 kernel_policy->cond_sdk_version.min_version,
8040 kernel_policy->cond_sdk_version.version,
8041 proc_platform(proc),
8042 proc_min_sdk(proc),
8043 proc_sdk(proc));
8044 if (kernel_policy->cond_sdk_version.platform != 0) {
8045 if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
8046 // Process does not match platform
8047 return FALSE;
8048 }
8049 }
8050
8051 if (kernel_policy->cond_sdk_version.min_version != 0) {
8052 if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
8053 // Process min version is older than required min version
8054 return FALSE;
8055 }
8056 }
8057
8058 if (kernel_policy->cond_sdk_version.version != 0) {
8059 if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
8060 // Process SDK version is older than required version
8061 return FALSE;
8062 }
8063 }
8064 }
8065 }
8066
8067 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
8068 NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
8069 if (kernel_policy->cond_custom_entitlement != NULL) {
8070 if (proc == NULL) {
8071 // No process found, cannot check entitlement
8072 return FALSE;
8073 }
8074 task_t task = proc_task(proc);
8075 if (task == NULL ||
8076 !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
8077 // Process is missing custom entitlement
8078 return FALSE;
8079 }
8080 }
8081 }
8082
8083 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8084 NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
8085 "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
8086 // Exact match requires the number of dots to match (no suffix matching allowed)
8087 bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
8088 necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
8089 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8090 if (domain_matches) {
8091 // No match, matches forbidden domain
8092 return FALSE;
8093 }
8094 } else {
8095 if (!domain_matches) {
8096 // No match, does not match required domain
8097 return FALSE;
8098 }
8099 }
8100 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8101 NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
8102 "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
8103 bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
8104 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8105 if (domain_matches) {
8106 // No match, matches forbidden domain
8107 return FALSE;
8108 }
8109 } else {
8110 if (!domain_matches) {
8111 // No match, does not match required domain
8112 return FALSE;
8113 }
8114 }
8115 }
8116
8117 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8118 struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
8119 if (filter != NULL && filter->filter != NULL) {
8120 bool domain_matches = net_bloom_filter_contains(filter->filter, domain.string, domain.length);
8121 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8122 if (domain_matches) {
8123 // No match, matches forbidden domain
8124 return FALSE;
8125 }
8126 } else {
8127 if (!domain_matches) {
8128 // No match, does not match required domain
8129 return FALSE;
8130 }
8131 }
8132 }
8133 }
8134
8135 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8136 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
8137 "NECP_KERNEL_CONDITION_ACCOUNT_ID",
8138 kernel_policy->cond_account_id, account_id);
8139 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8140 if (account_id == kernel_policy->cond_account_id) {
8141 // No match, matches forbidden account
8142 return FALSE;
8143 }
8144 } else {
8145 if (account_id != kernel_policy->cond_account_id) {
8146 // No match, does not match required account
8147 return FALSE;
8148 }
8149 }
8150 }
8151
8152 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
8153 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
8154 "NECP_KERNEL_CONDITION_PID",
8155 kernel_policy->cond_pid, pid);
8156 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
8157 if (pid == kernel_policy->cond_pid) {
8158 // No match, matches forbidden pid
8159 return FALSE;
8160 }
8161 if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
8162 return FALSE;
8163 }
8164 } else {
8165 if (pid != kernel_policy->cond_pid) {
8166 // No match, does not match required pid
8167 return FALSE;
8168 }
8169 if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
8170 return FALSE;
8171 }
8172 }
8173 }
8174
8175 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
8176 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
8177 "NECP_KERNEL_CONDITION_UID",
8178 kernel_policy->cond_uid, uid);
8179 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
8180 if (uid == kernel_policy->cond_uid) {
8181 // No match, matches forbidden uid
8182 return FALSE;
8183 }
8184 } else {
8185 if (uid != kernel_policy->cond_uid) {
8186 // No match, does not match required uid
8187 return FALSE;
8188 }
8189 }
8190 }
8191
8192 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
8193 NECP_DATA_TRACE_LOG_CONDITION3(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
8194 kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
8195 traffic_class, 0, 0);
8196 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
8197 if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
8198 traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
8199 // No match, matches forbidden traffic class
8200 return FALSE;
8201 }
8202 } else {
8203 if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
8204 traffic_class > kernel_policy->cond_traffic_class.end_tc) {
8205 // No match, does not match required traffic class
8206 return FALSE;
8207 }
8208 }
8209 }
8210
8211 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
8212 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
8213 "NECP_KERNEL_CONDITION_PROTOCOL",
8214 kernel_policy->cond_protocol, protocol);
8215 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
8216 if (protocol == kernel_policy->cond_protocol) {
8217 // No match, matches forbidden protocol
8218 return FALSE;
8219 }
8220 } else {
8221 if (protocol != kernel_policy->cond_protocol) {
8222 // No match, does not match required protocol
8223 return FALSE;
8224 }
8225 }
8226 }
8227
8228 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
8229 NECP_DATA_TRACE_LOG_CONDITION_STR3(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
8230 kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
8231 "n/a", "n/a", "n/a");
8232 bool matches_agent_type = FALSE;
8233 for (u_int32_t i = 0; i < num_required_agent_types; i++) {
8234 struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
8235 if ((strlen(kernel_policy->cond_agent_type.agent_domain) == 0 ||
8236 strncmp(required_agent_type->netagent_domain, kernel_policy->cond_agent_type.agent_domain, NETAGENT_DOMAINSIZE) == 0) &&
8237 (strlen(kernel_policy->cond_agent_type.agent_type) == 0 ||
8238 strncmp(required_agent_type->netagent_type, kernel_policy->cond_agent_type.agent_type, NETAGENT_TYPESIZE) == 0)) {
8239 // Found a required agent that matches
8240 matches_agent_type = TRUE;
8241 break;
8242 }
8243 }
8244 if (!matches_agent_type) {
8245 return FALSE;
8246 }
8247 }
8248
8249 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
8250 bool is_local = FALSE;
8251
8252 if (rt != NULL) {
8253 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt);
8254 } else {
8255 is_local = necp_is_route_local(remote);
8256 }
8257 if (info != NULL) {
8258 info->is_local = is_local;
8259 }
8260 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
8261 if (!is_local) {
8262 // Either no route to validate or no match for local networks
8263 return FALSE;
8264 }
8265 }
8266
8267 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
8268 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
8269 bool inRange = necp_is_addr_in_range((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, (struct sockaddr *)&kernel_policy->cond_local_end);
8270 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
8271 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
8272 if (inRange) {
8273 return FALSE;
8274 }
8275 } else {
8276 if (!inRange) {
8277 return FALSE;
8278 }
8279 }
8280 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
8281 bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, kernel_policy->cond_local_prefix);
8282 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
8283 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
8284 if (inSubnet) {
8285 return FALSE;
8286 }
8287 } else {
8288 if (!inSubnet) {
8289 return FALSE;
8290 }
8291 }
8292 }
8293 }
8294
8295 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
8296 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
8297 bool inRange = necp_is_addr_in_range((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, (struct sockaddr *)&kernel_policy->cond_remote_end);
8298 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
8299 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
8300 if (inRange) {
8301 return FALSE;
8302 }
8303 } else {
8304 if (!inRange) {
8305 return FALSE;
8306 }
8307 }
8308 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
8309 bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, kernel_policy->cond_remote_prefix);
8310 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
8311 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
8312 if (inSubnet) {
8313 return FALSE;
8314 }
8315 } else {
8316 if (!inSubnet) {
8317 return FALSE;
8318 }
8319 }
8320 }
8321 }
8322
8323 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
8324 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
8325 "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
8326 kernel_policy->cond_client_flags, client_flags);
8327 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
8328 if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
8329 // Flags do match, and condition is negative, fail.
8330 return FALSE;
8331 }
8332 } else {
8333 if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
8334 // Flags do not match, fail.
8335 return FALSE;
8336 }
8337 }
8338 }
8339
8340 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
8341 bool isEmpty = necp_addr_is_empty((struct sockaddr *)local);
8342 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
8343 "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
8344 0, isEmpty);
8345 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
8346 if (isEmpty) {
8347 return FALSE;
8348 }
8349 } else {
8350 if (!isEmpty) {
8351 return FALSE;
8352 }
8353 }
8354 }
8355
8356 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
8357 bool isEmpty = necp_addr_is_empty((struct sockaddr *)remote);
8358 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
8359 "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
8360 0, isEmpty);
8361 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
8362 if (isEmpty) {
8363 return FALSE;
8364 }
8365 } else {
8366 if (!isEmpty) {
8367 return FALSE;
8368 }
8369 }
8370 }
8371
8372 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
8373 u_int16_t remote_port = 0;
8374 if (((struct sockaddr *)remote)->sa_family == AF_INET || ((struct sockaddr *)remote)->sa_family == AF_INET6) {
8375 remote_port = ((struct sockaddr_in *)remote)->sin_port;
8376 }
8377 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
8378 "NECP_KERNEL_CONDITION_SCHEME_PORT",
8379 scheme_port, remote_port);
8380 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
8381 if (kernel_policy->cond_scheme_port == scheme_port ||
8382 kernel_policy->cond_scheme_port == remote_port) {
8383 return FALSE;
8384 }
8385 } else {
8386 if (kernel_policy->cond_scheme_port != scheme_port &&
8387 kernel_policy->cond_scheme_port != remote_port) {
8388 return FALSE;
8389 }
8390 }
8391 }
8392
8393 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
8394 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
8395 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
8396 kernel_policy->cond_packet_filter_tags,
8397 pf_tag);
8398 bool tags_matched = false;
8399 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
8400 if (pf_tag == PF_TAG_ID_STACK_DROP) {
8401 tags_matched = true;
8402 }
8403 }
8404
8405 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
8406 if (tags_matched) {
8407 return FALSE;
8408 }
8409 } else {
8410 if (!tags_matched) {
8411 return FALSE;
8412 }
8413 }
8414 }
8415
8416 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
8417 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
8418 if (is_loopback) {
8419 return FALSE;
8420 }
8421 } else {
8422 if (!is_loopback) {
8423 return FALSE;
8424 }
8425 }
8426 }
8427
8428 if (is_delegated && (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
8429 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
8430 if (real_is_platform_binary) {
8431 return FALSE;
8432 }
8433 } else {
8434 if (!real_is_platform_binary) {
8435 return FALSE;
8436 }
8437 }
8438 }
8439
8440 return TRUE;
8441 }
8442
8443 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)8444 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
8445 {
8446 return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
8447 }
8448
8449 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)8450 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)
8451 {
8452 struct socket *so = NULL;
8453 proc_t sock_proc = NULL;
8454 proc_t curr_proc = current_proc();
8455
8456 memset(info, 0, sizeof(struct necp_socket_info));
8457
8458 so = inp->inp_socket;
8459
8460 info->drop_order = drop_order;
8461 info->is_loopback = is_loopback;
8462 info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
8463
8464 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID) {
8465 info->uid = kauth_cred_getuid(so->so_cred);
8466 }
8467
8468 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
8469 info->traffic_class = so->so_traffic_class;
8470 }
8471
8472 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
8473 info->has_client = !uuid_is_null(inp->necp_client_uuid);
8474 }
8475
8476 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
8477 info->client_flags = 0;
8478 if (INP_NO_CONSTRAINED(inp)) {
8479 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
8480 }
8481 if (INP_NO_EXPENSIVE(inp)) {
8482 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
8483 }
8484 if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
8485 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
8486 }
8487 if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
8488 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
8489 }
8490 if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
8491 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
8492 }
8493 if (inp->inp_socket->so_flags1 & SOF1_INBOUND || override_is_inbound) {
8494 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
8495 }
8496 if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
8497 inp->inp_flags2 & INP2_EXTERNAL_PORT) {
8498 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
8499 }
8500 if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
8501 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
8502 }
8503 }
8504
8505 if ((necp_data_tracing_level && necp_data_tracing_proto) ||
8506 necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
8507 if (inp->inp_ip_p) {
8508 info->protocol = inp->inp_ip_p;
8509 } else {
8510 info->protocol = SOCK_PROTO(so);
8511 }
8512 }
8513
8514 if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
8515 u_int32_t responsible_application_id = 0;
8516
8517 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
8518 if (existing_mapping) {
8519 info->application_id = existing_mapping->id;
8520 }
8521
8522 #if defined(XNU_TARGET_OS_OSX)
8523 if (so->so_rpid > 0) {
8524 existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
8525 if (existing_mapping != NULL) {
8526 responsible_application_id = existing_mapping->id;
8527 }
8528 }
8529 #endif
8530
8531 if (responsible_application_id > 0) {
8532 info->real_application_id = info->application_id;
8533 info->application_id = responsible_application_id;
8534 info->used_responsible_pid = true;
8535 } else if (!(so->so_flags & SOF_DELEGATED)) {
8536 info->real_application_id = info->application_id;
8537 } else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
8538 struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
8539 if (real_existing_mapping) {
8540 info->real_application_id = real_existing_mapping->id;
8541 }
8542 }
8543 }
8544
8545 pid_t socket_pid =
8546 #if defined(XNU_TARGET_OS_OSX)
8547 info->used_responsible_pid ? so->so_rpid :
8548 #endif
8549 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
8550 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
8551 sock_proc = proc_find(socket_pid);
8552 if (socket_proc) {
8553 *socket_proc = sock_proc;
8554 }
8555 }
8556
8557 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
8558 const task_t task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
8559 info->is_entitled = necp_task_has_match_entitlement(task);
8560 if (!info->is_entitled) {
8561 // Task does not have entitlement, check the parent task
8562 necp_get_parent_is_entitled(task, info);
8563 }
8564 }
8565
8566 if ((necp_data_tracing_level && necp_data_tracing_pid) ||
8567 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID)) {
8568 info->pid = socket_pid;
8569 info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
8570 }
8571
8572 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
8573 info->is_platform_binary = necp_is_platform_binary(sock_proc ? sock_proc : curr_proc) ? true : false;
8574 }
8575
8576 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
8577 proc_t real_proc = curr_proc;
8578 bool release_real_proc = false;
8579 if (so->last_pid != proc_pid(real_proc)) {
8580 if (so->last_pid == socket_pid && sock_proc != NULL) {
8581 real_proc = sock_proc;
8582 } else {
8583 proc_t last_proc = proc_find(so->last_pid);
8584 if (last_proc != NULL) {
8585 real_proc = last_proc;
8586 release_real_proc = true;
8587 }
8588 }
8589 }
8590 if (real_proc != NULL) {
8591 info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
8592 if (release_real_proc) {
8593 proc_rele(real_proc);
8594 }
8595 }
8596 }
8597
8598 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
8599 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
8600 if (existing_mapping) {
8601 info->account_id = existing_mapping->id;
8602 }
8603 }
8604
8605 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
8606 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
8607 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
8608 info->domain = inp->inp_necp_attributes.inp_domain;
8609 }
8610
8611 if (override_bound_interface) {
8612 info->bound_interface_index = override_bound_interface;
8613 } else {
8614 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
8615 info->bound_interface_index = inp->inp_boundifp->if_index;
8616 }
8617 }
8618
8619 bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
8620 uuid_is_null(inp->necp_client_uuid) &&
8621 necp_socket_has_resolver_signature(inp));
8622 if ((necp_data_tracing_level && necp_data_tracing_port) ||
8623 necp_restrict_multicast ||
8624 needs_address_for_signature ||
8625 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
8626 if (override_local_addr != NULL) {
8627 if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
8628 memcpy(&info->local_addr, override_local_addr, override_local_addr->sa_len);
8629 if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
8630 struct sockaddr_in sin;
8631 in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
8632 memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
8633 memcpy(&info->local_addr, &sin, sin.sin_len);
8634 }
8635 } else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
8636 memcpy(&info->local_addr, override_local_addr, override_local_addr->sa_len);
8637 }
8638 } else {
8639 if (inp->inp_vflag & INP_IPV4) {
8640 ((struct sockaddr_in *)&info->local_addr)->sin_family = AF_INET;
8641 ((struct sockaddr_in *)&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
8642 ((struct sockaddr_in *)&info->local_addr)->sin_port = inp->inp_lport;
8643 memcpy(&((struct sockaddr_in *)&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
8644 } else if (inp->inp_vflag & INP_IPV6) {
8645 ((struct sockaddr_in6 *)&info->local_addr)->sin6_family = AF_INET6;
8646 ((struct sockaddr_in6 *)&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
8647 ((struct sockaddr_in6 *)&info->local_addr)->sin6_port = inp->inp_lport;
8648 memcpy(&((struct sockaddr_in6 *)&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
8649 }
8650 }
8651
8652 if (override_remote_addr != NULL) {
8653 if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
8654 memcpy(&info->remote_addr, override_remote_addr, override_remote_addr->sa_len);
8655 if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
8656 struct sockaddr_in sin;
8657 in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
8658 memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
8659 memcpy(&info->remote_addr, &sin, sin.sin_len);
8660 }
8661 } else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
8662 memcpy(&info->remote_addr, override_remote_addr, override_remote_addr->sa_len);
8663 }
8664 } else {
8665 if (inp->inp_vflag & INP_IPV4) {
8666 ((struct sockaddr_in *)&info->remote_addr)->sin_family = AF_INET;
8667 ((struct sockaddr_in *)&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
8668 ((struct sockaddr_in *)&info->remote_addr)->sin_port = inp->inp_fport;
8669 memcpy(&((struct sockaddr_in *)&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
8670 } else if (inp->inp_vflag & INP_IPV6) {
8671 ((struct sockaddr_in6 *)&info->remote_addr)->sin6_family = AF_INET6;
8672 ((struct sockaddr_in6 *)&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
8673 ((struct sockaddr_in6 *)&info->remote_addr)->sin6_port = inp->inp_fport;
8674 memcpy(&((struct sockaddr_in6 *)&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
8675 }
8676 }
8677 }
8678
8679 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
8680 // For checking sockets, only validate that there is an NECP client present. It will have
8681 // already checked for the signature.
8682 if (!uuid_is_null(inp->necp_client_uuid)) {
8683 info->has_system_signed_result = true;
8684 } else {
8685 info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
8686 }
8687 }
8688 }
8689
8690 #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)
8691
8692 static inline struct necp_kernel_socket_policy *
necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** policy_search_array,struct necp_socket_info * info,necp_kernel_policy_filter * return_filter,u_int32_t * 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 * return_netagent_array,u_int32_t * return_netagent_use_flags_array,size_t netagent_array_count,struct necp_client_parameter_netagent_type * 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)8693 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy **policy_search_array, struct necp_socket_info *info,
8694 necp_kernel_policy_filter *return_filter,
8695 u_int32_t *return_route_rule_id_array, size_t *return_route_rule_id_array_count, size_t route_rule_id_array_count,
8696 necp_kernel_policy_result *return_service_action, necp_kernel_policy_service *return_service,
8697 u_int32_t *return_netagent_array, u_int32_t *return_netagent_use_flags_array, size_t netagent_array_count,
8698 struct necp_client_parameter_netagent_type *required_agent_types,
8699 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,
8700 necp_kernel_policy_result *return_drop_dest_policy_result, necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
8701 u_int32_t *return_flow_divert_aggregate_unit, struct socket *so, int debug)
8702 {
8703 struct necp_kernel_socket_policy *matched_policy = NULL;
8704 u_int32_t skip_order = 0;
8705 u_int32_t skip_session_order = 0;
8706 bool skipped_ip_result = false;
8707 size_t route_rule_id_count = 0;
8708 int i;
8709 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
8710 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
8711 memset(&netagent_ids, 0, sizeof(netagent_ids));
8712 memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
8713 size_t netagent_cursor = 0;
8714 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
8715 if (return_drop_all_bypass != NULL) {
8716 *return_drop_all_bypass = drop_all_bypass;
8717 }
8718
8719 if (netagent_array_count > NECP_MAX_NETAGENTS) {
8720 netagent_array_count = NECP_MAX_NETAGENTS;
8721 }
8722
8723 // Pre-process domain for quick matching
8724 struct substring domain_substring = necp_trim_dots_and_stars(info->domain, info->domain ? strlen(info->domain) : 0);
8725 u_int8_t domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
8726
8727 if (return_filter != NULL) {
8728 *return_filter = 0;
8729 }
8730
8731 if (return_route_rule_id_array_count != NULL) {
8732 *return_route_rule_id_array_count = 0;
8733 }
8734
8735 if (return_service_action != NULL) {
8736 *return_service_action = 0;
8737 }
8738
8739 if (return_service != NULL) {
8740 return_service->identifier = 0;
8741 return_service->data = 0;
8742 }
8743
8744 // Do not subject layer-2 filter to NECP policies, return a PASS policy
8745 if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
8746 return &pass_policy;
8747 }
8748
8749 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
8750
8751 if (policy_search_array != NULL) {
8752 for (i = 0; policy_search_array[i] != NULL; i++) {
8753 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "EXAMINING");
8754
8755 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
8756 // We've hit a drop all rule
8757 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8758 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8759 if (return_drop_all_bypass != NULL) {
8760 *return_drop_all_bypass = drop_all_bypass;
8761 }
8762 }
8763 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8764 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "DROP - (session order > drop-all order)");
8765 break;
8766 }
8767 }
8768 if (necp_drop_dest_policy.entry_count != 0 &&
8769 necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
8770 // We've hit a drop by destination address rule
8771 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
8772 break;
8773 }
8774 if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
8775 // We've hit a drop order for this socket
8776 break;
8777 }
8778 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
8779 // Done skipping
8780 skip_order = 0;
8781 skip_session_order = 0;
8782 // If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
8783 if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
8784 *skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
8785 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIP (cleared saved skip)");
8786 }
8787 }
8788 if (skip_order) {
8789 if (policy_search_array[i]->order < skip_order) {
8790 // Skip this policy
8791 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
8792 // didn't, clear out the return value for skip ID when we are done with each session.'
8793 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
8794 skipped_ip_result = true;
8795 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIPPING IP RESULT");
8796 }
8797 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIP (session order < skip-order)");
8798 continue;
8799 } else {
8800 // Done skipping
8801 skip_order = 0;
8802 skip_session_order = 0;
8803 }
8804 } else if (skip_session_order) {
8805 // Skip this policy
8806 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
8807 // didn't, clear out the return value for skip ID when we are done with each session.'
8808 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
8809 skipped_ip_result = true;
8810 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIPPING IP RESULT");
8811 }
8812 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIP (skip-session-order)");
8813 continue;
8814 }
8815
8816 if (necp_socket_check_policy(policy_search_array[i], info->application_id, info->real_application_id, info->is_entitled, info->account_id, domain_substring, domain_dot_count, info->pid, info->pid_version, info->uid, info->bound_interface_index, info->traffic_class, info->protocol, &info->local_addr, &info->remote_addr, required_agent_types, num_required_agent_types, info->has_client, info->client_flags, info->is_platform_binary, info->has_system_signed_result, proc, pf_tag, info->scheme_port, rt, info->is_loopback, debug, info->real_is_platform_binary, info, info->is_delegated)) {
8817 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
8818 if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
8819 necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
8820 if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8821 *return_filter = control_unit;
8822 } else {
8823 // Preserve pre-existing connections only if all filters preserve.
8824 bool preserve_bit_off = false;
8825 if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
8826 (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
8827 preserve_bit_off = true;
8828 }
8829 *return_filter |= control_unit;
8830 if (preserve_bit_off == true) {
8831 *return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
8832 }
8833 }
8834 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
8835 NECPLOG(LOG_DEBUG, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Filter %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.filter_control_unit);
8836 }
8837 }
8838 continue;
8839 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
8840 if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
8841 return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
8842 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
8843 NECPLOG(LOG_DEBUG, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Route Rule %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.route_rule_id);
8844 }
8845 }
8846 continue;
8847 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
8848 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
8849 if (netagent_cursor < netagent_array_count) {
8850 bool agent_already_present = false;
8851 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
8852 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
8853 // Already present. Mark the "SCOPED" flag if flags are necessary.
8854 agent_already_present = true;
8855 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
8856 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
8857 netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
8858 }
8859 }
8860 }
8861
8862 if (!agent_already_present) {
8863 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
8864 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
8865 netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
8866 }
8867 netagent_cursor++;
8868 }
8869 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
8870 NECPLOG(LOG_DEBUG, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
8871 info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
8872 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
8873 policy_search_array[i]->result_parameter.netagent_id);
8874 }
8875 }
8876 continue;
8877 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
8878 bool agent_already_present = false;
8879 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
8880 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
8881 // Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
8882 agent_already_present = true;
8883 netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
8884 }
8885 }
8886 if (!agent_already_present && netagent_cursor < netagent_array_count) {
8887 // If not present, and flags are supported, add an entry with the "REMOVE" flag
8888 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
8889 netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8890 netagent_cursor++;
8891 }
8892 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
8893 NECPLOG(LOG_DEBUG, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
8894 info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
8895 policy_search_array[i]->result_parameter.netagent_id);
8896 }
8897 continue;
8898 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
8899 u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
8900 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
8901 /* For transparent proxies, accumulate the control unit and continue to the next policy */
8902 if (return_flow_divert_aggregate_unit != NULL) {
8903 *return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
8904 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
8905 NECPLOG(LOG_DEBUG, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) flow divert %u", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, control_unit);
8906 }
8907 }
8908 continue;
8909 }
8910 }
8911
8912 // Matched policy is a skip. Do skip and continue.
8913 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
8914 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "MATCHED SKIP POLICY");
8915 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
8916 skip_session_order = policy_search_array[i]->session_order + 1;
8917 if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
8918 *skip_policy_id = policy_search_array[i]->id;
8919 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
8920 NECPLOG(LOG_DEBUG, "Socket Policy: MATCHED SKIP POLICY (Application %d Real Application %d BoundInterface %d Proto %d) set skip_policy_id %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, *skip_policy_id);
8921 }
8922 }
8923 continue;
8924 }
8925
8926 // Matched an allow unentitled, which clears any drop order
8927 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
8928 info->drop_order = 0;
8929 continue;
8930 }
8931
8932 // Passed all tests, found a match
8933 matched_policy = policy_search_array[i];
8934 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "MATCHED POLICY");
8935 break;
8936 }
8937 }
8938 }
8939
8940 if (return_netagent_array != NULL) {
8941 if (return_netagent_use_flags_array != NULL) {
8942 memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count);
8943 memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count);
8944 } else {
8945 for (size_t netagent_i = 0; netagent_i < netagent_array_count; netagent_i++) {
8946 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
8947 return_netagent_array[netagent_i] = netagent_ids[netagent_i];
8948 } else {
8949 return_netagent_array[netagent_i] = 0;
8950 }
8951 }
8952 }
8953 }
8954
8955 if (return_route_rule_id_array_count != NULL) {
8956 *return_route_rule_id_array_count = route_rule_id_count;
8957 }
8958 return matched_policy;
8959 }
8960
8961 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)8962 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
8963 {
8964 bool found_match = FALSE;
8965 ifaddr_t ifa;
8966 union necp_sockaddr_union address_storage;
8967 int family = AF_INET;
8968
8969 ifnet_head_lock_shared();
8970 ifnet_t interface = ifindex2ifnet[interface_index];
8971 ifnet_head_done();
8972
8973 if (inp == NULL || interface == NULL) {
8974 return FALSE;
8975 }
8976
8977 if (inp->inp_vflag & INP_IPV4) {
8978 family = AF_INET;
8979 } else if (inp->inp_vflag & INP_IPV6) {
8980 family = AF_INET6;
8981 } else {
8982 return FALSE;
8983 }
8984
8985 // Match socket address against interface addresses
8986 ifnet_lock_shared(interface);
8987 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
8988 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
8989 if (address_storage.sa.sa_family != family) {
8990 continue;
8991 }
8992
8993 if (family == AF_INET) {
8994 if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
8995 found_match = TRUE;
8996 break;
8997 }
8998 } else if (family == AF_INET6) {
8999 if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
9000 found_match = TRUE;
9001 break;
9002 }
9003 }
9004 }
9005 }
9006 ifnet_lock_done(interface);
9007
9008 return found_match;
9009 }
9010
9011 static inline bool
necp_socket_is_connected(struct inpcb * inp)9012 necp_socket_is_connected(struct inpcb *inp)
9013 {
9014 return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
9015 }
9016
9017 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)9018 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
9019 {
9020 if (necp_pass_loopback > 0 && necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
9021 return NECP_BYPASS_TYPE_LOOPBACK;
9022 } else if (necp_is_intcoproc(inp, NULL)) {
9023 return NECP_BYPASS_TYPE_INTCOPROC;
9024 }
9025
9026 return NECP_BYPASS_TYPE_NONE;
9027 }
9028
9029 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)9030 necp_socket_ip_tunnel_tso(struct inpcb *inp)
9031 {
9032 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
9033 ifnet_t tunnel_interface = NULL;
9034
9035 ifnet_head_lock_shared();
9036 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
9037 ifnet_head_done();
9038
9039 if (tunnel_interface != NULL) {
9040 tcp_set_tso(intotcpcb(inp), tunnel_interface);
9041 }
9042 }
9043
9044 static inline void
necp_unscope(struct inpcb * inp)9045 necp_unscope(struct inpcb *inp)
9046 {
9047 // If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
9048 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
9049 inp->inp_flags &= ~INP_BOUND_IF;
9050 inp->inp_boundifp = NULL;
9051 }
9052 }
9053
9054 static inline void
necp_clear_tunnel(struct inpcb * inp)9055 necp_clear_tunnel(struct inpcb *inp)
9056 {
9057 if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
9058 inp->inp_flags &= ~INP_BOUND_IF;
9059 inp->inp_boundifp = NULL;
9060 }
9061 }
9062
9063 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)9064 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
9065 {
9066 struct socket *so = NULL;
9067 necp_kernel_policy_filter filter_control_unit = 0;
9068 struct necp_kernel_socket_policy *matched_policy = NULL;
9069 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9070 necp_kernel_policy_result service_action = 0;
9071 necp_kernel_policy_service service = { 0, 0 };
9072 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9073 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9074 proc_t socket_proc = NULL;
9075 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
9076
9077 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
9078 memset(&netagent_ids, 0, sizeof(netagent_ids));
9079 int netagent_cursor;
9080
9081 struct necp_socket_info info;
9082
9083 u_int32_t flow_divert_aggregate_unit = 0;
9084
9085 if (inp == NULL) {
9086 return NECP_KERNEL_POLICY_ID_NONE;
9087 }
9088
9089 // Ignore invalid addresses
9090 if (override_local_addr != NULL &&
9091 !necp_address_is_valid(override_local_addr)) {
9092 override_local_addr = NULL;
9093 }
9094 if (override_remote_addr != NULL &&
9095 !necp_address_is_valid(override_remote_addr)) {
9096 override_remote_addr = NULL;
9097 }
9098
9099 so = inp->inp_socket;
9100
9101 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
9102
9103 // Don't lock. Possible race condition, but we don't want the performance hit.
9104 if (necp_kernel_socket_policies_count == 0 ||
9105 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0)) {
9106 if (necp_drop_all_order > 0 || drop_order > 0) {
9107 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9108 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9109 inp->inp_policyresult.policy_gencount = 0;
9110 inp->inp_policyresult.app_id = 0;
9111 inp->inp_policyresult.flowhash = 0;
9112 inp->inp_policyresult.results.filter_control_unit = 0;
9113 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9114 inp->inp_policyresult.results.route_rule_id = 0;
9115 if (necp_socket_bypass(override_local_addr, override_remote_addr, inp) != NECP_BYPASS_TYPE_NONE) {
9116 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
9117 } else {
9118 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9119 }
9120 }
9121 return NECP_KERNEL_POLICY_ID_NONE;
9122 }
9123
9124 // Check for loopback exception
9125 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
9126 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
9127 // Mark socket as a pass
9128 necp_unscope(inp);
9129 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9130 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9131 inp->inp_policyresult.policy_gencount = 0;
9132 inp->inp_policyresult.app_id = 0;
9133 inp->inp_policyresult.flowhash = 0;
9134 inp->inp_policyresult.results.filter_control_unit = 0;
9135 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9136 inp->inp_policyresult.results.route_rule_id = 0;
9137 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
9138 return NECP_KERNEL_POLICY_ID_NONE;
9139 }
9140
9141 // Lock
9142 lck_rw_lock_shared(&necp_kernel_policy_lock);
9143 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));
9144
9145 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid);
9146 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - INP UPDATE", "START", 0, 0);
9147
9148 // Check info
9149 u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
9150 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
9151 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
9152 inp->inp_policyresult.flowhash == flowhash) {
9153 // If already matched this socket on this generation of table, skip
9154
9155 // Unlock
9156 lck_rw_done(&necp_kernel_policy_lock);
9157
9158 if (socket_proc) {
9159 proc_rele(socket_proc);
9160 }
9161
9162 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9163 NECPLOG(LOG_DEBUG, "Socket Policy - INP UPDATE - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
9164 inp->inp_socket, info.bound_interface_index, info.protocol,
9165 inp->inp_policyresult.policy_id,
9166 inp->inp_policyresult.results.result,
9167 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
9168 }
9169 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - INP UPDATE", "CACHED <MATCHED>", inp->inp_policyresult.policy_id, 0);
9170 return inp->inp_policyresult.policy_id;
9171 }
9172
9173 inp->inp_policyresult.app_id = info.application_id;
9174
9175 // Match socket to policy
9176 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9177 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
9178 size_t route_rule_id_array_count = 0;
9179
9180 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)], &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, 0, socket_proc ? socket_proc : current_proc(), 0, &skip_policy_id, inp->inp_route.ro_rt, &drop_dest_policy_result, &drop_all_bypass, &flow_divert_aggregate_unit, so, debug);
9181
9182 // Check for loopback exception again after the policy match
9183 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
9184 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
9185 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
9186 // Mark socket as a pass
9187 necp_unscope(inp);
9188 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9189 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9190 inp->inp_policyresult.policy_gencount = 0;
9191 inp->inp_policyresult.app_id = 0;
9192 inp->inp_policyresult.flowhash = 0;
9193 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
9194 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9195 inp->inp_policyresult.results.route_rule_id = 0;
9196 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
9197
9198 // Unlock
9199 lck_rw_done(&necp_kernel_policy_lock);
9200
9201 if (socket_proc) {
9202 proc_rele(socket_proc);
9203 }
9204
9205 return NECP_KERNEL_POLICY_ID_NONE;
9206 }
9207
9208 // Verify netagents
9209 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
9210 struct necp_uuid_id_mapping *mapping = NULL;
9211 u_int32_t netagent_id = netagent_ids[netagent_cursor];
9212 if (netagent_id == 0) {
9213 continue;
9214 }
9215 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
9216 if (mapping != NULL) {
9217 u_int32_t agent_flags = 0;
9218 agent_flags = netagent_get_flags(mapping->uuid);
9219 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
9220 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
9221 continue;
9222 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
9223 if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
9224 int trigger_error = 0;
9225 trigger_error = netagent_kernel_trigger(mapping->uuid);
9226 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9227 NECPLOG(LOG_DEBUG, "Socket Policy: Triggering inactive agent, error %d", trigger_error);
9228 }
9229 }
9230
9231 // Mark socket as a drop if required agent is not active
9232 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9233 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9234 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9235 inp->inp_policyresult.flowhash = flowhash;
9236 inp->inp_policyresult.results.filter_control_unit = 0;
9237 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9238 inp->inp_policyresult.results.route_rule_id = 0;
9239 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9240
9241 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9242 NECPLOG(LOG_DEBUG, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because agent is not active", info.bound_interface_index, info.protocol);
9243 }
9244
9245 // Unlock
9246 lck_rw_done(&necp_kernel_policy_lock);
9247
9248 if (socket_proc) {
9249 proc_rele(socket_proc);
9250 }
9251
9252 return NECP_KERNEL_POLICY_ID_NONE;
9253 }
9254 }
9255 }
9256 }
9257
9258 u_int32_t route_rule_id = 0;
9259 if (route_rule_id_array_count == 1) {
9260 route_rule_id = route_rule_id_array[0];
9261 } else if (route_rule_id_array_count > 1) {
9262 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
9263 }
9264
9265 bool reset_tcp_tunnel_interface = false;
9266 bool send_local_network_denied_event = false;
9267 if (matched_policy) {
9268 // For PASS policy result, clear previous rescope / tunnel inteface
9269 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
9270 (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
9271 necp_unscope(inp);
9272 necp_clear_tunnel(inp);
9273 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9274 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, 0);
9275 }
9276 }
9277 matched_policy_id = matched_policy->id;
9278 inp->inp_policyresult.policy_id = matched_policy->id;
9279 inp->inp_policyresult.skip_policy_id = skip_policy_id;
9280 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9281 inp->inp_policyresult.flowhash = flowhash;
9282 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
9283 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9284 inp->inp_policyresult.results.route_rule_id = route_rule_id;
9285 inp->inp_policyresult.results.result = matched_policy->result;
9286 memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
9287
9288 if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
9289 inp->inp_policyresult.app_id = info.real_application_id;
9290 }
9291
9292 if (necp_socket_is_connected(inp) &&
9293 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
9294 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
9295 NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
9296 sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
9297 } else if (necp_socket_is_connected(inp) &&
9298 matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
9299 info.protocol == IPPROTO_TCP) {
9300 // Reset TCP socket interface based parameters if tunnel policy changes
9301 reset_tcp_tunnel_interface = true;
9302 }
9303
9304 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9305 NECPLOG(LOG_DEBUG, "Socket Policy: %p (BoundInterface %d Proto %d) Policy %d Skip %d Result %d Parameter %d", inp->inp_socket, info.bound_interface_index, info.protocol, matched_policy->id, skip_policy_id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index);
9306 }
9307
9308 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
9309 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
9310 // Trigger the event that we dropped due to a local network policy
9311 send_local_network_denied_event = true;
9312 }
9313 } else {
9314 bool drop_all = false;
9315 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
9316 // Mark socket as a drop if set
9317 drop_all = true;
9318 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
9319 drop_all_bypass = necp_check_drop_all_bypass_result(socket_proc ? socket_proc : current_proc());
9320 }
9321 }
9322
9323 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
9324 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(NULL, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id);
9325 if (flow_divert_control_unit != 0) {
9326 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9327 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9328 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9329 inp->inp_policyresult.flowhash = flowhash;
9330 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
9331 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9332 inp->inp_policyresult.results.route_rule_id = route_rule_id;
9333 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
9334 inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
9335 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - INP UPDATE", "FLOW DIVERT <ROUTE RULE>", 0, 0);
9336 } else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
9337 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9338 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9339 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9340 inp->inp_policyresult.flowhash = flowhash;
9341 inp->inp_policyresult.results.filter_control_unit = 0;
9342 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9343 inp->inp_policyresult.results.route_rule_id = 0;
9344 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9345 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - INP UPDATE", "DROP <NO MATCH>", 0, 0);
9346 } else {
9347 // Mark non-matching socket so we don't re-check it
9348 necp_unscope(inp);
9349 if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
9350 necp_clear_tunnel(inp);
9351 }
9352 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9353 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - INP UPDATE", "socket unscoped for <NO MATCH>", inp->inp_policyresult.policy_id, 0);
9354 }
9355 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9356 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9357 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9358 inp->inp_policyresult.flowhash = flowhash;
9359 inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
9360 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9361 inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
9362 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
9363 }
9364 }
9365
9366 if (necp_check_missing_client_drop(socket_proc ? socket_proc : current_proc(), &info) ||
9367 necp_check_restricted_multicast_drop(socket_proc ? socket_proc : current_proc(), &info, false)) {
9368 // Mark as drop
9369 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9370 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9371 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9372 inp->inp_policyresult.flowhash = flowhash;
9373 inp->inp_policyresult.results.filter_control_unit = 0;
9374 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9375 inp->inp_policyresult.results.route_rule_id = 0;
9376 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9377 }
9378
9379 // Unlock
9380 lck_rw_done(&necp_kernel_policy_lock);
9381
9382 if (reset_tcp_tunnel_interface) {
9383 // Update MSS when not holding the policy lock to avoid recursive locking
9384 tcp_mtudisc(inp, 0);
9385
9386 // Update TSO flag based on the tunnel interface
9387 necp_socket_ip_tunnel_tso(inp);
9388 }
9389
9390 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
9391 inp->inp_policyresult.network_denied_notifies++;
9392 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
9393 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
9394 NETPOLICY_NETWORKTYPE_LOCAL);
9395 }
9396
9397 if (socket_proc) {
9398 proc_rele(socket_proc);
9399 }
9400
9401 return matched_policy_id;
9402 }
9403
9404 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)9405 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)
9406 {
9407 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9408 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9409 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9410 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9411 "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
9412 cond_bound_interface_index, bound_interface_index);
9413 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9414 if (bound_interface_index == cond_bound_interface_index) {
9415 // No match, matches forbidden interface
9416 return FALSE;
9417 }
9418 } else {
9419 if (bound_interface_index != cond_bound_interface_index) {
9420 // No match, does not match required interface
9421 return FALSE;
9422 }
9423 }
9424 } else {
9425 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
9426 if (bound_interface_index != 0) {
9427 // No match, requires a non-bound packet
9428 return FALSE;
9429 }
9430 }
9431 }
9432
9433 if (kernel_policy->condition_mask == 0) {
9434 return TRUE;
9435 }
9436
9437 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
9438 necp_kernel_policy_id matched_policy_id =
9439 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
9440 NECP_DATA_TRACE_LOG_CONDITION3(debug, "IP", false,
9441 "NECP_KERNEL_CONDITION_POLICY_ID",
9442 kernel_policy->cond_policy_id, 0, 0,
9443 matched_policy_id, socket_policy_id, socket_skip_policy_id);
9444 if (matched_policy_id != kernel_policy->cond_policy_id) {
9445 // No match, does not match required id
9446 return FALSE;
9447 }
9448 }
9449
9450 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
9451 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", false,
9452 "NECP_KERNEL_CONDITION_LAST_INTERFACE",
9453 kernel_policy->cond_last_interface_index, last_interface_index);
9454 if (last_interface_index != kernel_policy->cond_last_interface_index) {
9455 return FALSE;
9456 }
9457 }
9458
9459 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9460 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9461 "NECP_KERNEL_CONDITION_PROTOCOL",
9462 kernel_policy->cond_protocol, protocol);
9463 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9464 if (protocol == kernel_policy->cond_protocol) {
9465 // No match, matches forbidden protocol
9466 return FALSE;
9467 }
9468 } else {
9469 if (protocol != kernel_policy->cond_protocol) {
9470 // No match, does not match required protocol
9471 return FALSE;
9472 }
9473 }
9474 }
9475
9476 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9477 bool is_local = FALSE;
9478
9479 if (rt != NULL) {
9480 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt);
9481 } else {
9482 is_local = necp_is_route_local(remote);
9483 }
9484 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", false, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
9485 if (!is_local) {
9486 // Either no route to validate or no match for local networks
9487 return FALSE;
9488 }
9489 }
9490
9491 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9492 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9493 bool inRange = necp_is_addr_in_range((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, (struct sockaddr *)&kernel_policy->cond_local_end);
9494 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9495 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9496 if (inRange) {
9497 return FALSE;
9498 }
9499 } else {
9500 if (!inRange) {
9501 return FALSE;
9502 }
9503 }
9504 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9505 bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, kernel_policy->cond_local_prefix);
9506 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
9507 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9508 if (inSubnet) {
9509 return FALSE;
9510 }
9511 } else {
9512 if (!inSubnet) {
9513 return FALSE;
9514 }
9515 }
9516 }
9517 }
9518
9519 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9520 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9521 bool inRange = necp_is_addr_in_range((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, (struct sockaddr *)&kernel_policy->cond_remote_end);
9522 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9523 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9524 if (inRange) {
9525 return FALSE;
9526 }
9527 } else {
9528 if (!inRange) {
9529 return FALSE;
9530 }
9531 }
9532 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9533 bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, kernel_policy->cond_remote_prefix);
9534 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
9535 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9536 if (inSubnet) {
9537 return FALSE;
9538 }
9539 } else {
9540 if (!inSubnet) {
9541 return FALSE;
9542 }
9543 }
9544 }
9545 }
9546
9547 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9548 u_int16_t remote_port = 0;
9549 if (((struct sockaddr *)remote)->sa_family == AF_INET || ((struct sockaddr *)remote)->sa_family == AF_INET6) {
9550 remote_port = ((struct sockaddr_in *)remote)->sin_port;
9551 }
9552 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9553 "NECP_KERNEL_CONDITION_SCHEME_PORT",
9554 0, remote_port);
9555 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9556 if (kernel_policy->cond_scheme_port == remote_port) {
9557 return FALSE;
9558 }
9559 } else {
9560 if (kernel_policy->cond_scheme_port != remote_port) {
9561 return FALSE;
9562 }
9563 }
9564 }
9565
9566 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9567 bool tags_matched = false;
9568 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9569 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9570 kernel_policy->cond_packet_filter_tags, pf_tag);
9571 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9572 if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
9573 tags_matched = true;
9574 }
9575
9576 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9577 if (tags_matched) {
9578 return FALSE;
9579 }
9580 } else {
9581 if (!tags_matched) {
9582 return FALSE;
9583 }
9584 }
9585 }
9586 }
9587
9588 return TRUE;
9589 }
9590
9591 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)9592 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)
9593 {
9594 u_int32_t skip_order = 0;
9595 u_int32_t skip_session_order = 0;
9596 struct necp_kernel_ip_output_policy *matched_policy = NULL;
9597 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)];
9598 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
9599 size_t route_rule_id_count = 0;
9600 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9601 if (return_drop_all_bypass != NULL) {
9602 *return_drop_all_bypass = drop_all_bypass;
9603 }
9604
9605 if (return_route_rule_id != NULL) {
9606 *return_route_rule_id = 0;
9607 }
9608
9609 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9610
9611 if (policy_search_array != NULL) {
9612 for (int i = 0; policy_search_array[i] != NULL; i++) {
9613 NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "EXAMINING");
9614 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
9615 // We've hit a drop all rule
9616 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
9617 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
9618 if (return_drop_all_bypass != NULL) {
9619 *return_drop_all_bypass = drop_all_bypass;
9620 }
9621 }
9622 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
9623 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "DROP (session order > drop-all order)");
9624 break;
9625 }
9626 }
9627 if (necp_drop_dest_policy.entry_count > 0 &&
9628 necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
9629 // We've hit a drop by destination address rule
9630 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
9631 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "DROP (destination address rule)");
9632 break;
9633 }
9634 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
9635 // Done skipping
9636 skip_order = 0;
9637 skip_session_order = 0;
9638 }
9639 if (skip_order) {
9640 if (policy_search_array[i]->order < skip_order) {
9641 // Skip this policy
9642 NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "SKIP (session order < skip-order)");
9643 continue;
9644 } else {
9645 // Done skipping
9646 skip_order = 0;
9647 skip_session_order = 0;
9648 }
9649 } else if (skip_session_order) {
9650 // Skip this policy
9651 NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "SKIP (skip-session-order)");
9652 continue;
9653 }
9654
9655 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)) {
9656 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
9657 if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
9658 route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
9659 }
9660 continue;
9661 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
9662 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
9663 skip_session_order = policy_search_array[i]->session_order + 1;
9664 NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "MATCHED SKIP POLICY");
9665 continue;
9666 }
9667
9668 // Passed all tests, found a match
9669 matched_policy = policy_search_array[i];
9670 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "MATCHED POLICY");
9671 break;
9672 }
9673 }
9674 }
9675
9676 if (route_rule_id_count == 1) {
9677 *return_route_rule_id = route_rule_id_array[0];
9678 } else if (route_rule_id_count > 1) {
9679 *return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
9680 }
9681
9682 return matched_policy;
9683 }
9684
9685 static inline bool
necp_output_bypass(struct mbuf * packet)9686 necp_output_bypass(struct mbuf *packet)
9687 {
9688 if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
9689 return true;
9690 }
9691 if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
9692 return true;
9693 }
9694 if (necp_is_intcoproc(NULL, packet)) {
9695 return true;
9696 }
9697 return false;
9698 }
9699
9700 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)9701 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
9702 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
9703 {
9704 struct ip *ip = NULL;
9705 int hlen = sizeof(struct ip);
9706 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9707 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9708 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9709 struct necp_kernel_ip_output_policy *matched_policy = NULL;
9710 u_int16_t protocol = 0;
9711 u_int32_t bound_interface_index = 0;
9712 u_int32_t last_interface_index = 0;
9713 union necp_sockaddr_union local_addr = { };
9714 union necp_sockaddr_union remote_addr = { };
9715 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9716 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9717 u_int16_t pf_tag = 0;
9718
9719 if (result) {
9720 *result = 0;
9721 }
9722
9723 if (result_parameter) {
9724 memset(result_parameter, 0, sizeof(*result_parameter));
9725 }
9726
9727 if (packet == NULL) {
9728 return NECP_KERNEL_POLICY_ID_NONE;
9729 }
9730
9731 socket_policy_id = necp_get_policy_id_from_packet(packet);
9732 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
9733 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
9734
9735 // Exit early for an empty list
9736 // Don't lock. Possible race condition, but we don't want the performance hit.
9737 if (necp_kernel_ip_output_policies_count == 0 ||
9738 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
9739 if (necp_drop_all_order > 0) {
9740 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9741 if (result) {
9742 if (necp_output_bypass(packet)) {
9743 *result = NECP_KERNEL_POLICY_RESULT_PASS;
9744 } else {
9745 *result = NECP_KERNEL_POLICY_RESULT_DROP;
9746 }
9747 }
9748 }
9749
9750 return matched_policy_id;
9751 }
9752
9753 // Check for loopback exception
9754 if (necp_output_bypass(packet)) {
9755 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9756 if (result) {
9757 *result = NECP_KERNEL_POLICY_RESULT_PASS;
9758 }
9759 return matched_policy_id;
9760 }
9761
9762 last_interface_index = necp_get_last_interface_index_from_packet(packet);
9763
9764 // Process packet to get relevant fields
9765 ip = mtod(packet, struct ip *);
9766 #ifdef _IP_VHL
9767 hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
9768 #else
9769 hlen = ip->ip_hl << 2;
9770 #endif
9771
9772 protocol = ip->ip_p;
9773
9774 if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
9775 (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
9776 ipoa->ipoa_boundif != IFSCOPE_NONE) {
9777 bound_interface_index = ipoa->ipoa_boundif;
9778 }
9779
9780 local_addr.sin.sin_family = AF_INET;
9781 local_addr.sin.sin_len = sizeof(struct sockaddr_in);
9782 memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
9783
9784 remote_addr.sin.sin_family = AF_INET;
9785 remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
9786 memcpy(&((struct sockaddr_in *)&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
9787
9788 switch (protocol) {
9789 case IPPROTO_TCP: {
9790 struct tcphdr th;
9791 if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
9792 m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
9793 ((struct sockaddr_in *)&local_addr)->sin_port = th.th_sport;
9794 ((struct sockaddr_in *)&remote_addr)->sin_port = th.th_dport;
9795 }
9796 break;
9797 }
9798 case IPPROTO_UDP: {
9799 struct udphdr uh;
9800 if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
9801 m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
9802 ((struct sockaddr_in *)&local_addr)->sin_port = uh.uh_sport;
9803 ((struct sockaddr_in *)&remote_addr)->sin_port = uh.uh_dport;
9804 }
9805 break;
9806 }
9807 default: {
9808 ((struct sockaddr_in *)&local_addr)->sin_port = 0;
9809 ((struct sockaddr_in *)&remote_addr)->sin_port = 0;
9810 break;
9811 }
9812 }
9813
9814 // Match packet to policy
9815 lck_rw_lock_shared(&necp_kernel_policy_lock);
9816 u_int32_t route_rule_id = 0;
9817
9818 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0);
9819 NECP_DATA_TRACE_LOG_IP(debug, "IPv4", "START");
9820
9821 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);
9822 if (matched_policy) {
9823 matched_policy_id = matched_policy->id;
9824 if (result) {
9825 *result = matched_policy->result;
9826 }
9827
9828 if (result_parameter) {
9829 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
9830 }
9831
9832 if (route_rule_id != 0 &&
9833 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
9834 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
9835 }
9836
9837 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9838 NECPLOG(LOG_DEBUG, "IP Output: (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);
9839 }
9840 } else {
9841 bool drop_all = false;
9842 /*
9843 * Apply drop-all only to packets which have never matched a primary policy (check
9844 * if the packet saved policy id is none or falls within the socket policy id range).
9845 */
9846 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
9847 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
9848 drop_all = true;
9849 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
9850 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
9851 }
9852 }
9853 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
9854 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9855 if (result) {
9856 *result = NECP_KERNEL_POLICY_RESULT_DROP;
9857 NECP_DATA_TRACE_LOG_IP(debug, "IPv4", "DROP <NO MATCH>");
9858 }
9859 } else if (route_rule_id != 0 &&
9860 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
9861 // If we matched a route rule, mark it
9862 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
9863 }
9864 }
9865
9866 lck_rw_done(&necp_kernel_policy_lock);
9867
9868 return matched_policy_id;
9869 }
9870
9871 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)9872 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
9873 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
9874 {
9875 struct ip6_hdr *ip6 = NULL;
9876 int next = -1;
9877 int offset = 0;
9878 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9879 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9880 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9881 struct necp_kernel_ip_output_policy *matched_policy = NULL;
9882 u_int16_t protocol = 0;
9883 u_int32_t bound_interface_index = 0;
9884 u_int32_t last_interface_index = 0;
9885 union necp_sockaddr_union local_addr = { };
9886 union necp_sockaddr_union remote_addr = { };
9887 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9888 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9889 u_int16_t pf_tag = 0;
9890
9891 if (result) {
9892 *result = 0;
9893 }
9894
9895 if (result_parameter) {
9896 memset(result_parameter, 0, sizeof(*result_parameter));
9897 }
9898
9899 if (packet == NULL) {
9900 return NECP_KERNEL_POLICY_ID_NONE;
9901 }
9902
9903 socket_policy_id = necp_get_policy_id_from_packet(packet);
9904 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
9905 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
9906
9907 // Exit early for an empty list
9908 // Don't lock. Possible race condition, but we don't want the performance hit.
9909 if (necp_kernel_ip_output_policies_count == 0 ||
9910 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
9911 if (necp_drop_all_order > 0) {
9912 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9913 if (result) {
9914 if (necp_output_bypass(packet)) {
9915 *result = NECP_KERNEL_POLICY_RESULT_PASS;
9916 } else {
9917 *result = NECP_KERNEL_POLICY_RESULT_DROP;
9918 }
9919 }
9920 }
9921
9922 return matched_policy_id;
9923 }
9924
9925 // Check for loopback exception
9926 if (necp_output_bypass(packet)) {
9927 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9928 if (result) {
9929 *result = NECP_KERNEL_POLICY_RESULT_PASS;
9930 }
9931 return matched_policy_id;
9932 }
9933
9934 last_interface_index = necp_get_last_interface_index_from_packet(packet);
9935
9936 // Process packet to get relevant fields
9937 ip6 = mtod(packet, struct ip6_hdr *);
9938
9939 if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
9940 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
9941 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
9942 bound_interface_index = ip6oa->ip6oa_boundif;
9943 }
9944
9945 ((struct sockaddr_in6 *)&local_addr)->sin6_family = AF_INET6;
9946 ((struct sockaddr_in6 *)&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9947 memcpy(&((struct sockaddr_in6 *)&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
9948
9949 ((struct sockaddr_in6 *)&remote_addr)->sin6_family = AF_INET6;
9950 ((struct sockaddr_in6 *)&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9951 memcpy(&((struct sockaddr_in6 *)&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
9952
9953 offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
9954 if (offset >= 0 && packet->m_pkthdr.len >= offset) {
9955 protocol = next;
9956 switch (protocol) {
9957 case IPPROTO_TCP: {
9958 struct tcphdr th;
9959 if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
9960 m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
9961 ((struct sockaddr_in6 *)&local_addr)->sin6_port = th.th_sport;
9962 ((struct sockaddr_in6 *)&remote_addr)->sin6_port = th.th_dport;
9963 }
9964 break;
9965 }
9966 case IPPROTO_UDP: {
9967 struct udphdr uh;
9968 if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
9969 m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
9970 ((struct sockaddr_in6 *)&local_addr)->sin6_port = uh.uh_sport;
9971 ((struct sockaddr_in6 *)&remote_addr)->sin6_port = uh.uh_dport;
9972 }
9973 break;
9974 }
9975 default: {
9976 ((struct sockaddr_in6 *)&local_addr)->sin6_port = 0;
9977 ((struct sockaddr_in6 *)&remote_addr)->sin6_port = 0;
9978 break;
9979 }
9980 }
9981 }
9982
9983 // Match packet to policy
9984 lck_rw_lock_shared(&necp_kernel_policy_lock);
9985 u_int32_t route_rule_id = 0;
9986
9987 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0);
9988 NECP_DATA_TRACE_LOG_IP(debug, "IPv6", "START");
9989
9990 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);
9991 if (matched_policy) {
9992 matched_policy_id = matched_policy->id;
9993 if (result) {
9994 *result = matched_policy->result;
9995 }
9996
9997 if (result_parameter) {
9998 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
9999 }
10000
10001 if (route_rule_id != 0 &&
10002 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10003 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10004 }
10005
10006 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10007 NECPLOG(LOG_DEBUG, "IP6 Output: (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);
10008 }
10009 } else {
10010 bool drop_all = false;
10011 /*
10012 * Apply drop-all only to packets which have never matched a primary policy (check
10013 * if the packet saved policy id is none or falls within the socket policy id range).
10014 */
10015 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
10016 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
10017 drop_all = true;
10018 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10019 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10020 }
10021 }
10022 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10023 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10024 if (result) {
10025 *result = NECP_KERNEL_POLICY_RESULT_DROP;
10026 NECP_DATA_TRACE_LOG_IP(debug, "IPv6", "DROP <NO MATCH>");
10027 }
10028 } else if (route_rule_id != 0 &&
10029 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10030 // If we matched a route rule, mark it
10031 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10032 }
10033 }
10034
10035 lck_rw_done(&necp_kernel_policy_lock);
10036
10037 return matched_policy_id;
10038 }
10039
10040 // Utilities
10041 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)10042 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
10043 {
10044 int cmp = 0;
10045
10046 if (addr == NULL || range_start == NULL || range_end == NULL) {
10047 return FALSE;
10048 }
10049
10050 /* Must be greater than or equal to start */
10051 cmp = necp_addr_compare(addr, range_start, 1);
10052 if (cmp != 0 && cmp != 1) {
10053 return FALSE;
10054 }
10055
10056 /* Must be less than or equal to end */
10057 cmp = necp_addr_compare(addr, range_end, 1);
10058 if (cmp != 0 && cmp != -1) {
10059 return FALSE;
10060 }
10061
10062 return TRUE;
10063 }
10064
10065 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)10066 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
10067 {
10068 int cmp = 0;
10069
10070 if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
10071 return FALSE;
10072 }
10073
10074 /* Must be greater than or equal to start */
10075 cmp = necp_addr_compare(inner_range_start, range_start, 1);
10076 if (cmp != 0 && cmp != 1) {
10077 return FALSE;
10078 }
10079
10080 /* Must be less than or equal to end */
10081 cmp = necp_addr_compare(inner_range_end, range_end, 1);
10082 if (cmp != 0 && cmp != -1) {
10083 return FALSE;
10084 }
10085
10086 return TRUE;
10087 }
10088
10089 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)10090 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
10091 {
10092 if (addr == NULL || subnet_addr == NULL) {
10093 return FALSE;
10094 }
10095
10096 if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
10097 return FALSE;
10098 }
10099
10100 switch (addr->sa_family) {
10101 case AF_INET: {
10102 if (satosin(subnet_addr)->sin_port != 0 &&
10103 satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
10104 return FALSE;
10105 }
10106 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
10107 }
10108 case AF_INET6: {
10109 if (satosin6(subnet_addr)->sin6_port != 0 &&
10110 satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
10111 return FALSE;
10112 }
10113 if (satosin6(addr)->sin6_scope_id &&
10114 satosin6(subnet_addr)->sin6_scope_id &&
10115 satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
10116 return FALSE;
10117 }
10118 return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
10119 }
10120 default: {
10121 return FALSE;
10122 }
10123 }
10124
10125 return FALSE;
10126 }
10127
10128 /*
10129 * Return values:
10130 * -1: sa1 < sa2
10131 * 0: sa1 == sa2
10132 * 1: sa1 > sa2
10133 * 2: Not comparable or error
10134 */
10135 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)10136 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
10137 {
10138 int result = 0;
10139 int port_result = 0;
10140
10141 if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
10142 return 2;
10143 }
10144
10145 if (sa1->sa_len == 0) {
10146 return 0;
10147 }
10148
10149 switch (sa1->sa_family) {
10150 case AF_INET: {
10151 if (sa1->sa_len != sizeof(struct sockaddr_in)) {
10152 return 2;
10153 }
10154
10155 result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
10156
10157 if (check_port) {
10158 if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
10159 port_result = -1;
10160 } else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
10161 port_result = 1;
10162 }
10163
10164 if (result == 0) {
10165 result = port_result;
10166 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
10167 return 2;
10168 }
10169 }
10170
10171 break;
10172 }
10173 case AF_INET6: {
10174 if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
10175 return 2;
10176 }
10177
10178 if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
10179 return 2;
10180 }
10181
10182 result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
10183
10184 if (check_port) {
10185 if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
10186 port_result = -1;
10187 } else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
10188 port_result = 1;
10189 }
10190
10191 if (result == 0) {
10192 result = port_result;
10193 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
10194 return 2;
10195 }
10196 }
10197
10198 break;
10199 }
10200 default: {
10201 result = memcmp(sa1, sa2, sa1->sa_len);
10202 break;
10203 }
10204 }
10205
10206 if (result < 0) {
10207 result = (-1);
10208 } else if (result > 0) {
10209 result = (1);
10210 }
10211
10212 return result;
10213 }
10214
10215 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * p1,u_int8_t * p2,u_int32_t bits)10216 necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits)
10217 {
10218 u_int8_t mask;
10219
10220 /* Handle null pointers */
10221 if (p1 == NULL || p2 == NULL) {
10222 return p1 == p2;
10223 }
10224
10225 while (bits >= 8) {
10226 if (*p1++ != *p2++) {
10227 return FALSE;
10228 }
10229 bits -= 8;
10230 }
10231
10232 if (bits > 0) {
10233 mask = ~((1 << (8 - bits)) - 1);
10234 if ((*p1 & mask) != (*p2 & mask)) {
10235 return FALSE;
10236 }
10237 }
10238 return TRUE;
10239 }
10240
10241 static bool
necp_addr_is_empty(struct sockaddr * addr)10242 necp_addr_is_empty(struct sockaddr *addr)
10243 {
10244 if (addr == NULL) {
10245 return TRUE;
10246 }
10247
10248 if (addr->sa_len == 0) {
10249 return TRUE;
10250 }
10251
10252 switch (addr->sa_family) {
10253 case AF_INET: {
10254 static struct sockaddr_in ipv4_empty_address = {
10255 .sin_len = sizeof(struct sockaddr_in),
10256 .sin_family = AF_INET,
10257 .sin_port = 0,
10258 .sin_addr = { .s_addr = 0 }, // 0.0.0.0
10259 .sin_zero = {0},
10260 };
10261 if (necp_addr_compare(addr, (struct sockaddr *)&ipv4_empty_address, 0) == 0) {
10262 return TRUE;
10263 } else {
10264 return FALSE;
10265 }
10266 }
10267 case AF_INET6: {
10268 static struct sockaddr_in6 ipv6_empty_address = {
10269 .sin6_len = sizeof(struct sockaddr_in6),
10270 .sin6_family = AF_INET6,
10271 .sin6_port = 0,
10272 .sin6_flowinfo = 0,
10273 .sin6_addr = IN6ADDR_ANY_INIT, // ::
10274 .sin6_scope_id = 0,
10275 };
10276 if (necp_addr_compare(addr, (struct sockaddr *)&ipv6_empty_address, 0) == 0) {
10277 return TRUE;
10278 } else {
10279 return FALSE;
10280 }
10281 }
10282 default:
10283 return FALSE;
10284 }
10285
10286 return FALSE;
10287 }
10288
10289 static bool
necp_update_qos_marking(struct ifnet * ifp,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id)10290 necp_update_qos_marking(struct ifnet *ifp, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
10291 {
10292 bool qos_marking = FALSE;
10293 int exception_index = 0;
10294 struct necp_route_rule *route_rule = NULL;
10295
10296 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
10297 if (route_rule == NULL) {
10298 qos_marking = FALSE;
10299 goto done;
10300 }
10301
10302 if (route_rule->match_netagent_id != 0) {
10303 if (netagent_array == NULL || netagent_array_count == 0) {
10304 // No agents, ignore rule
10305 goto done;
10306 }
10307 bool found_match = FALSE;
10308 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
10309 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
10310 found_match = TRUE;
10311 break;
10312 }
10313 }
10314 if (!found_match) {
10315 // Agents don't match, ignore rule
10316 goto done;
10317 }
10318 }
10319
10320 qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
10321
10322 if (ifp == NULL) {
10323 goto done;
10324 }
10325
10326 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
10327 if (route_rule->exception_if_indices[exception_index] == 0) {
10328 break;
10329 }
10330 if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
10331 continue;
10332 }
10333 if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
10334 qos_marking = TRUE;
10335 if (necp_debug > 2) {
10336 NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
10337 route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
10338 }
10339 goto done;
10340 }
10341 }
10342
10343 if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
10344 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
10345 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
10346 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
10347 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
10348 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp))) {
10349 qos_marking = TRUE;
10350 if (necp_debug > 2) {
10351 NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d for Rule %d Allowed %d",
10352 route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
10353 route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule_id, qos_marking);
10354 }
10355 goto done;
10356 }
10357 done:
10358 if (necp_debug > 1) {
10359 NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
10360 route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
10361 }
10362 return qos_marking;
10363 }
10364
10365 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)10366 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)
10367 {
10368 bool new_qos_marking = old_qos_marking;
10369 struct ifnet *ifp = interface;
10370
10371 if (net_qos_policy_restricted == 0) {
10372 return new_qos_marking;
10373 }
10374
10375 /*
10376 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
10377 */
10378 if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
10379 return new_qos_marking;
10380 }
10381
10382 lck_rw_lock_shared(&necp_kernel_policy_lock);
10383
10384 if (ifp == NULL && route != NULL) {
10385 ifp = route->rt_ifp;
10386 }
10387 /*
10388 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
10389 */
10390 if (ifp == NULL || route_rule_id == 0) {
10391 new_qos_marking = FALSE;
10392 goto done;
10393 }
10394
10395 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
10396 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
10397 if (aggregate_route_rule != NULL) {
10398 int index = 0;
10399 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
10400 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
10401 if (sub_route_rule_id == 0) {
10402 break;
10403 }
10404 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
10405 if (new_qos_marking == TRUE) {
10406 break;
10407 }
10408 }
10409 }
10410 } else {
10411 new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
10412 }
10413 /*
10414 * Now that we have an interface we remember the gencount
10415 */
10416 *qos_marking_gencount = necp_kernel_socket_policies_gencount;
10417
10418 done:
10419 lck_rw_done(&necp_kernel_policy_lock);
10420 return new_qos_marking;
10421 }
10422
10423 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)10424 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
10425 {
10426 bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
10427
10428 if (net_qos_policy_restricted == 0) {
10429 return;
10430 }
10431 if (inp->inp_socket == NULL) {
10432 return;
10433 }
10434 if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
10435 return;
10436 }
10437
10438 qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
10439
10440 if (qos_marking == TRUE) {
10441 inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
10442 } else {
10443 inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
10444 }
10445 }
10446
10447 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)10448 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
10449 {
10450 if (ifp != NULL &&
10451 (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
10452 ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
10453 return true;
10454 }
10455 if (delegated_ifp != NULL &&
10456 (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
10457 delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
10458 return true;
10459 }
10460 return false;
10461 }
10462
10463 static bool
necp_route_is_allowed_inner(struct rtentry * route,struct ifnet * ifp,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * interface_type_denied)10464 necp_route_is_allowed_inner(struct rtentry *route, struct ifnet *ifp, u_int32_t *netagent_array, size_t netagent_array_count,
10465 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
10466 {
10467 bool default_is_allowed = TRUE;
10468 u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
10469 int exception_index = 0;
10470 struct ifnet *delegated_ifp = NULL;
10471 struct necp_route_rule *route_rule = NULL;
10472
10473 route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
10474 if (route_rule == NULL) {
10475 return TRUE;
10476 }
10477
10478 if (route_rule->match_netagent_id != 0) {
10479 if (netagent_array == NULL || netagent_array_count == 0) {
10480 // No agents, ignore rule
10481 return TRUE;
10482 }
10483 bool found_match = FALSE;
10484 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
10485 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
10486 found_match = TRUE;
10487 break;
10488 }
10489 }
10490 if (!found_match) {
10491 // Agents don't match, ignore rule
10492 return TRUE;
10493 }
10494 }
10495
10496 default_is_allowed = (route_rule->default_action == NECP_ROUTE_RULE_DENY_INTERFACE) ? FALSE : TRUE;
10497 if (ifp == NULL && route != NULL) {
10498 ifp = route->rt_ifp;
10499 }
10500 if (ifp == NULL) {
10501 if (necp_debug > 1 && !default_is_allowed) {
10502 NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
10503 }
10504 return default_is_allowed;
10505 }
10506
10507 delegated_ifp = ifp->if_delegated.ifp;
10508 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
10509 if (route_rule->exception_if_indices[exception_index] == 0) {
10510 break;
10511 }
10512 if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
10513 (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
10514 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
10515 const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
10516 if (necp_debug > 1 && lqm_abort) {
10517 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
10518 route_rule->exception_if_indices[exception_index], route_rule_id);
10519 }
10520 return false;
10521 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
10522 if (necp_debug > 1) {
10523 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Allowed %d", route_rule->exception_if_indices[exception_index], route_rule_id, ((route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_INTERFACE) ? FALSE : TRUE));
10524 }
10525 return (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_INTERFACE) ? FALSE : TRUE;
10526 }
10527 }
10528 }
10529
10530 if (IFNET_IS_CELLULAR(ifp)) {
10531 if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
10532 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
10533 if (interface_type_denied != NULL) {
10534 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
10535 }
10536 // Mark aggregate action as deny
10537 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
10538 }
10539 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
10540 if (interface_type_denied != NULL) {
10541 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
10542 }
10543 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
10544 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
10545 route_rule->cellular_action == NECP_ROUTE_RULE_DENY_INTERFACE)) {
10546 // Deny wins if there is a conflict
10547 type_aggregate_action = route_rule->cellular_action;
10548 }
10549 }
10550 }
10551
10552 if (IFNET_IS_WIFI(ifp)) {
10553 if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
10554 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
10555 if (interface_type_denied != NULL) {
10556 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
10557 }
10558 // Mark aggregate action as deny
10559 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
10560 }
10561 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
10562 if (interface_type_denied != NULL) {
10563 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
10564 }
10565 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
10566 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
10567 route_rule->wifi_action == NECP_ROUTE_RULE_DENY_INTERFACE)) {
10568 // Deny wins if there is a conflict
10569 type_aggregate_action = route_rule->wifi_action;
10570 }
10571 }
10572 }
10573
10574 if (IFNET_IS_COMPANION_LINK(ifp)) {
10575 if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
10576 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
10577 if (interface_type_denied != NULL) {
10578 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
10579 }
10580 // Mark aggregate action as deny
10581 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
10582 }
10583 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
10584 if (interface_type_denied != NULL) {
10585 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
10586 }
10587 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
10588 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
10589 route_rule->companion_action == NECP_ROUTE_RULE_DENY_INTERFACE)) {
10590 // Deny wins if there is a conflict
10591 type_aggregate_action = route_rule->companion_action;
10592 }
10593 }
10594 }
10595
10596 if (IFNET_IS_WIRED(ifp)) {
10597 if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
10598 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
10599 if (interface_type_denied != NULL) {
10600 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
10601 }
10602 // Mark aggregate action as deny
10603 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
10604 }
10605 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
10606 if (interface_type_denied != NULL) {
10607 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
10608 }
10609 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
10610 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
10611 route_rule->wired_action == NECP_ROUTE_RULE_DENY_INTERFACE)) {
10612 // Deny wins if there is a conflict
10613 type_aggregate_action = route_rule->wired_action;
10614 }
10615 }
10616 }
10617
10618 if (IFNET_IS_EXPENSIVE(ifp)) {
10619 if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
10620 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
10621 // Mark aggregate action as deny
10622 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
10623 }
10624 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
10625 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
10626 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
10627 route_rule->expensive_action == NECP_ROUTE_RULE_DENY_INTERFACE)) {
10628 // Deny wins if there is a conflict
10629 type_aggregate_action = route_rule->expensive_action;
10630 }
10631 }
10632 }
10633
10634 if (IFNET_IS_CONSTRAINED(ifp)) {
10635 if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
10636 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
10637 // Mark aggregate action as deny
10638 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
10639 }
10640 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
10641 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
10642 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
10643 route_rule->constrained_action == NECP_ROUTE_RULE_DENY_INTERFACE)) {
10644 // Deny wins if there is a conflict
10645 type_aggregate_action = route_rule->constrained_action;
10646 }
10647 }
10648 }
10649
10650 if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
10651 if (necp_debug > 1) {
10652 NECPLOG(LOG_DEBUG, "Route Allowed: C:%d WF:%d W:%d E:%d Cmpn:%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_id, ((type_aggregate_action == NECP_ROUTE_RULE_DENY_INTERFACE) ? FALSE : TRUE));
10653 }
10654 return (type_aggregate_action == NECP_ROUTE_RULE_DENY_INTERFACE) ? FALSE : TRUE;
10655 }
10656
10657 if (necp_debug > 1 && !default_is_allowed) {
10658 NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
10659 }
10660 return default_is_allowed;
10661 }
10662
10663 static bool
necp_route_is_allowed(struct rtentry * route,struct ifnet * interface,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * interface_type_denied)10664 necp_route_is_allowed(struct rtentry *route, struct ifnet *interface, u_int32_t *netagent_array, size_t netagent_array_count,
10665 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
10666 {
10667 if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
10668 if (necp_debug > 1) {
10669 NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
10670 }
10671 return TRUE;
10672 }
10673
10674 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
10675 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
10676 if (aggregate_route_rule != NULL) {
10677 int index = 0;
10678 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
10679 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
10680 if (sub_route_rule_id == 0) {
10681 break;
10682 }
10683 if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
10684 return FALSE;
10685 }
10686 }
10687 }
10688 } else {
10689 return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
10690 }
10691
10692 return TRUE;
10693 }
10694
10695 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)10696 necp_route_rule_matches_agents(u_int32_t route_rule_id)
10697 {
10698 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
10699 if (route_rule == NULL) {
10700 return false;
10701 }
10702
10703 return route_rule->match_netagent_id != 0;
10704 }
10705
10706 static uint32_t
necp_route_get_netagent(struct rtentry * route,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,bool * remove)10707 necp_route_get_netagent(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove)
10708 {
10709 if (remove == NULL) {
10710 return 0;
10711 }
10712
10713 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
10714 if (route_rule == NULL) {
10715 return 0;
10716 }
10717
10718 // No netagent, skip
10719 if (route_rule->netagent_id == 0) {
10720 return 0;
10721 }
10722
10723 if (route_rule->match_netagent_id != 0) {
10724 if (netagent_array == NULL || netagent_array_count == 0) {
10725 // No agents, ignore rule
10726 return 0;
10727 }
10728 bool found_match = FALSE;
10729 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
10730 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
10731 found_match = TRUE;
10732 break;
10733 }
10734 }
10735 if (!found_match) {
10736 // Agents don't match, ignore rule
10737 return 0;
10738 }
10739 }
10740
10741 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
10742 if (ifp == NULL) {
10743 // No interface, apply the default action
10744 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
10745 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
10746 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
10747 return route_rule->netagent_id;
10748 }
10749 return 0;
10750 }
10751
10752 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
10753 if (route_rule->exception_if_indices[exception_index] == 0) {
10754 break;
10755 }
10756 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
10757 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
10758 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
10759 route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
10760 *remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
10761 return route_rule->netagent_id;
10762 }
10763 return 0;
10764 }
10765 }
10766
10767 if (ifp->if_type == IFT_CELLULAR &&
10768 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
10769 if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
10770 route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
10771 *remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
10772 return route_rule->netagent_id;
10773 }
10774 return 0;
10775 }
10776
10777 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
10778 route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
10779 if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
10780 route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
10781 *remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
10782 return route_rule->netagent_id;
10783 }
10784 return 0;
10785 }
10786
10787 if (IFNET_IS_COMPANION_LINK(ifp) &&
10788 route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
10789 if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
10790 route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
10791 *remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
10792 return route_rule->netagent_id;
10793 }
10794 return 0;
10795 }
10796
10797 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
10798 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
10799 if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
10800 route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
10801 *remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
10802 return route_rule->netagent_id;
10803 }
10804 return 0;
10805 }
10806
10807 if (ifp->if_eflags & IFEF_EXPENSIVE &&
10808 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
10809 if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
10810 route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
10811 *remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
10812 return route_rule->netagent_id;
10813 }
10814 return 0;
10815 }
10816
10817 if (ifp->if_xflags & IFXF_CONSTRAINED &&
10818 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
10819 if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
10820 route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
10821 *remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
10822 return route_rule->netagent_id;
10823 }
10824 return 0;
10825 }
10826
10827 // No more specific case matched, apply the default action
10828 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
10829 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
10830 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
10831 return route_rule->netagent_id;
10832 }
10833
10834 return 0;
10835 }
10836
10837 static uint32_t
necp_route_get_flow_divert_inner(struct rtentry * route,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id)10838 necp_route_get_flow_divert_inner(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
10839 {
10840 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
10841 if (route_rule == NULL) {
10842 return 0;
10843 }
10844
10845 // No control unit, skip
10846 if (route_rule->control_unit == 0) {
10847 return 0;
10848 }
10849
10850 if (route_rule->match_netagent_id != 0) {
10851 if (netagent_array == NULL || netagent_array_count == 0) {
10852 // No agents, ignore rule
10853 return 0;
10854 }
10855 bool found_match = FALSE;
10856 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
10857 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
10858 found_match = TRUE;
10859 break;
10860 }
10861 }
10862 if (!found_match) {
10863 // Agents don't match, ignore rule
10864 return 0;
10865 }
10866 }
10867
10868 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
10869 if (ifp == NULL) {
10870 // No interface, apply the default action
10871 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10872 return route_rule->control_unit;
10873 }
10874 return 0;
10875 }
10876
10877 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
10878 if (route_rule->exception_if_indices[exception_index] == 0) {
10879 break;
10880 }
10881 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
10882 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
10883 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10884 return route_rule->control_unit;
10885 }
10886 return 0;
10887 }
10888 }
10889
10890 if (ifp->if_type == IFT_CELLULAR &&
10891 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
10892 if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10893 return route_rule->control_unit;
10894 }
10895 return 0;
10896 }
10897
10898 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
10899 route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10900 if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10901 return route_rule->control_unit;
10902 }
10903 return 0;
10904 }
10905
10906 if (IFNET_IS_COMPANION_LINK(ifp) &&
10907 route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10908 if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10909 return route_rule->control_unit;
10910 }
10911 return 0;
10912 }
10913
10914 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
10915 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
10916 if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10917 return route_rule->control_unit;
10918 }
10919 return 0;
10920 }
10921
10922 if (ifp->if_eflags & IFEF_EXPENSIVE &&
10923 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
10924 if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10925 return route_rule->control_unit;
10926 }
10927 return 0;
10928 }
10929
10930 if (ifp->if_xflags & IFXF_CONSTRAINED &&
10931 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
10932 if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10933 return route_rule->control_unit;
10934 }
10935 return 0;
10936 }
10937
10938 // No more specific case matched, apply the default action
10939 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
10940 return route_rule->control_unit;
10941 }
10942 return 0;
10943 }
10944
10945 static uint32_t
necp_route_get_flow_divert(struct rtentry * route,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id)10946 necp_route_get_flow_divert(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
10947 {
10948 if ((route == NULL && netagent_array == NULL) || route_rule_id == 0) {
10949 return 0;
10950 }
10951
10952 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
10953 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
10954 if (aggregate_route_rule != NULL) {
10955 int index = 0;
10956 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
10957 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
10958 if (sub_route_rule_id == 0) {
10959 break;
10960 }
10961 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
10962 if (control_unit != 0) {
10963 return control_unit;
10964 }
10965 }
10966 }
10967 } else {
10968 return necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
10969 }
10970
10971 return 0;
10972 }
10973
10974 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)10975 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
10976 {
10977 bool is_allowed = TRUE;
10978 u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
10979 if (route_rule_id != 0 &&
10980 interface != NULL) {
10981 lck_rw_lock_shared(&necp_kernel_policy_lock);
10982 is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
10983 lck_rw_done(&necp_kernel_policy_lock);
10984 }
10985 return is_allowed;
10986 }
10987
10988 static bool
necp_netagents_allow_traffic(u_int32_t * netagent_ids,size_t netagent_id_count)10989 necp_netagents_allow_traffic(u_int32_t *netagent_ids, size_t netagent_id_count)
10990 {
10991 size_t netagent_cursor;
10992 for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
10993 struct necp_uuid_id_mapping *mapping = NULL;
10994 u_int32_t netagent_id = netagent_ids[netagent_cursor];
10995 if (netagent_id == 0) {
10996 continue;
10997 }
10998 mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
10999 if (mapping != NULL) {
11000 u_int32_t agent_flags = 0;
11001 agent_flags = netagent_get_flags(mapping->uuid);
11002 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
11003 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
11004 continue;
11005 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
11006 return FALSE;
11007 }
11008 }
11009 }
11010 }
11011 return TRUE;
11012 }
11013
11014 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)11015 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
11016 {
11017 bool allowed_to_receive = TRUE;
11018
11019 if (pf_tag == PF_TAG_ID_STACK_DROP &&
11020 (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
11021 allowed_to_receive = FALSE;
11022 }
11023
11024 return allowed_to_receive;
11025 }
11026
11027 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)11028 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)
11029 {
11030 u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
11031 bool allowed_to_receive = TRUE;
11032 struct necp_socket_info info;
11033 u_int32_t flowhash = 0;
11034 necp_kernel_policy_result service_action = 0;
11035 necp_kernel_policy_service service = { 0, 0 };
11036 u_int32_t route_rule_id = 0;
11037 struct rtentry *route = NULL;
11038 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
11039 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11040 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11041 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
11042 proc_t socket_proc = NULL;
11043 necp_kernel_policy_filter filter_control_unit = 0;
11044 u_int32_t pass_flags = 0;
11045 u_int32_t flow_divert_aggregate_unit = 0;
11046 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
11047
11048 memset(&netagent_ids, 0, sizeof(netagent_ids));
11049
11050 if (return_policy_id) {
11051 *return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11052 }
11053 if (return_skip_policy_id) {
11054 *return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11055 }
11056 if (return_route_rule_id) {
11057 *return_route_rule_id = 0;
11058 }
11059 if (return_pass_flags) {
11060 *return_pass_flags = 0;
11061 }
11062
11063 if (inp == NULL) {
11064 goto done;
11065 }
11066
11067 route = inp->inp_route.ro_rt;
11068
11069 struct socket *so = inp->inp_socket;
11070
11071 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
11072
11073 // Don't lock. Possible race condition, but we don't want the performance hit.
11074 if (necp_kernel_socket_policies_count == 0 ||
11075 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0)) {
11076 if (necp_drop_all_order > 0 || drop_order > 0) {
11077 if (necp_socket_bypass(override_local_addr, override_remote_addr, inp) != NECP_BYPASS_TYPE_NONE) {
11078 allowed_to_receive = TRUE;
11079 } else {
11080 allowed_to_receive = FALSE;
11081 }
11082 }
11083 goto done;
11084 }
11085
11086 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
11087 if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
11088 bool policies_have_changed = FALSE;
11089 bool route_allowed = TRUE;
11090
11091 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
11092 policies_have_changed = TRUE;
11093 } else {
11094 if (inp->inp_policyresult.results.route_rule_id != 0) {
11095 lck_rw_lock_shared(&necp_kernel_policy_lock);
11096 if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
11097 route_allowed = FALSE;
11098 }
11099 lck_rw_done(&necp_kernel_policy_lock);
11100 }
11101 }
11102
11103 if (!policies_have_changed) {
11104 if (!route_allowed ||
11105 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
11106 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11107 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
11108 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
11109 allowed_to_receive = FALSE;
11110 } else {
11111 if (return_policy_id) {
11112 *return_policy_id = inp->inp_policyresult.policy_id;
11113 }
11114 if (return_skip_policy_id) {
11115 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
11116 }
11117 if (return_route_rule_id) {
11118 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
11119 }
11120 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
11121 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
11122 }
11123 }
11124 goto done;
11125 }
11126 }
11127
11128 // Check for loopback exception
11129 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
11130 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
11131 allowed_to_receive = TRUE;
11132 goto done;
11133 }
11134
11135 // Actually calculate policy result
11136 lck_rw_lock_shared(&necp_kernel_policy_lock);
11137 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));
11138
11139 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid);
11140 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - DATA PATH", "START", 0, 0);
11141
11142 flowhash = necp_socket_calc_flowhash_locked(&info);
11143 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
11144 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
11145 inp->inp_policyresult.flowhash == flowhash) {
11146 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
11147 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11148 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
11149 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
11150 (inp->inp_policyresult.results.route_rule_id != 0 &&
11151 !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
11152 allowed_to_receive = FALSE;
11153 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - DATA PATH", "CACHED - DROP", 0, 0);
11154 } else {
11155 if (return_policy_id) {
11156 *return_policy_id = inp->inp_policyresult.policy_id;
11157 }
11158 if (return_route_rule_id) {
11159 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
11160 }
11161 if (return_skip_policy_id) {
11162 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
11163 }
11164 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
11165 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
11166 }
11167 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11168 NECPLOG(LOG_DEBUG, "Socket Policy - Send/Recv - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Skip %d Result %d Parameter %d",
11169 inp->inp_socket, info.bound_interface_index, info.protocol,
11170 inp->inp_policyresult.policy_id,
11171 inp->inp_policyresult.skip_policy_id,
11172 inp->inp_policyresult.results.result,
11173 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
11174 }
11175 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - DATA PATH", "CACHED <MATCHED>",
11176 return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
11177 }
11178 lck_rw_done(&necp_kernel_policy_lock);
11179 goto done;
11180 }
11181
11182 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11183 size_t route_rule_id_array_count = 0;
11184 struct necp_kernel_socket_policy *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)], &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, 0, socket_proc ? socket_proc : current_proc(), pf_tag, return_skip_policy_id, inp->inp_route.ro_rt, &drop_dest_policy_result, &drop_all_bypass, &flow_divert_aggregate_unit, so, debug);
11185
11186 // Check for loopback exception again after the policy match
11187 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
11188 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
11189 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
11190 // If policies haven't changed since last evaluation, do not update filter result in order to
11191 // preserve the very first filter result for the socket. Otherwise, update the filter result to
11192 // allow content filter to detect and drop pre-existing flows.
11193 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
11194 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
11195 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
11196 }
11197 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
11198 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
11199 }
11200 allowed_to_receive = TRUE;
11201 lck_rw_done(&necp_kernel_policy_lock);
11202 goto done;
11203 }
11204
11205 if (route_rule_id_array_count == 1) {
11206 route_rule_id = route_rule_id_array[0];
11207 } else if (route_rule_id_array_count > 1) {
11208 route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11209 }
11210
11211 bool send_local_network_denied_event = false;
11212 if (matched_policy != NULL) {
11213 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
11214 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
11215 // Trigger the event that we dropped due to a local network policy
11216 send_local_network_denied_event = true;
11217 }
11218
11219 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
11220 matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11221 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
11222 matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
11223 (route_rule_id != 0 &&
11224 !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
11225 !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
11226 allowed_to_receive = FALSE;
11227 } else {
11228 if (return_policy_id) {
11229 *return_policy_id = matched_policy->id;
11230 }
11231 if (return_route_rule_id) {
11232 *return_route_rule_id = route_rule_id;
11233 }
11234 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
11235 pass_flags = matched_policy->result_parameter.pass_flags;
11236 }
11237 // If policies haven't changed since last evaluation, do not update filter result in order to
11238 // preserve the very first filter result for the socket. Otherwise, update the filter result to
11239 // allow content filter to detect and drop pre-existing flows.
11240 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
11241 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
11242 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
11243 }
11244 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
11245 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
11246 }
11247 }
11248
11249 if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
11250 NECPLOG(LOG_DEBUG, "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>",
11251 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);
11252 }
11253 } else {
11254 bool drop_all = false;
11255 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
11256 drop_all = true;
11257 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11258 drop_all_bypass = necp_check_drop_all_bypass_result(socket_proc ? socket_proc : current_proc());
11259 }
11260 }
11261 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11262 allowed_to_receive = FALSE;
11263 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - DATA PATH", "DROP - NO MATCH", 0, 0);
11264 } else {
11265 if (return_policy_id) {
11266 *return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11267 }
11268 if (return_route_rule_id) {
11269 *return_route_rule_id = route_rule_id;
11270 }
11271
11272 // If policies haven't changed since last evaluation, do not update filter result in order to
11273 // preserve the very first filter result for the socket. Otherwise, update the filter result to
11274 // allow content filter to detect and drop pre-existing flows.
11275 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
11276 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
11277 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
11278 }
11279 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
11280 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
11281 }
11282 }
11283 }
11284
11285 if (necp_check_restricted_multicast_drop(socket_proc ? socket_proc : current_proc(), &info, true)) {
11286 allowed_to_receive = FALSE;
11287 NECP_DATA_TRACE_LOG_SOCKET(debug, "SOCKET - DATA PATH", "DROP - MULTICAST", 0, 0);
11288 }
11289
11290 lck_rw_done(&necp_kernel_policy_lock);
11291
11292 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
11293 inp->inp_policyresult.network_denied_notifies++;
11294 necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
11295 ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
11296 NETPOLICY_NETWORKTYPE_LOCAL);
11297 }
11298
11299 done:
11300 if (return_pass_flags != NULL) {
11301 *return_pass_flags = pass_flags;
11302 }
11303
11304 if (pf_tag != 0 && allowed_to_receive) {
11305 allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
11306 }
11307
11308 if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
11309 soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
11310 }
11311
11312 if (socket_proc) {
11313 proc_rele(socket_proc);
11314 }
11315
11316 return allowed_to_receive;
11317 }
11318
11319 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)11320 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)
11321 {
11322 struct sockaddr_in local = {};
11323 struct sockaddr_in remote = {};
11324 local.sin_family = remote.sin_family = AF_INET;
11325 local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
11326 local.sin_port = local_port;
11327 remote.sin_port = remote_port;
11328 memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
11329 memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
11330
11331 return necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, input_interface,
11332 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
11333 }
11334
11335 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)11336 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)
11337 {
11338 struct sockaddr_in6 local = {};
11339 struct sockaddr_in6 remote = {};
11340 local.sin6_family = remote.sin6_family = AF_INET6;
11341 local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
11342 local.sin6_port = local_port;
11343 remote.sin6_port = remote_port;
11344 memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
11345 memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
11346
11347 return necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, input_interface,
11348 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
11349 }
11350
11351 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)11352 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,
11353 u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
11354 {
11355 return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
11356 return_policy_id, return_route_rule_id,
11357 return_skip_policy_id, return_pass_flags);
11358 }
11359
11360 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)11361 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
11362 necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
11363 {
11364 if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
11365 return EINVAL;
11366 }
11367
11368 // Mark ID for Pass and IP Tunnel
11369 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
11370 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
11371 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
11372 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
11373 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
11374 } else {
11375 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11376 }
11377 packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
11378 if (route_rule_id != 0) {
11379 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11380 } else {
11381 packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
11382 }
11383 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);
11384
11385 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
11386 skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
11387 // Only mark the skip policy if it is a valid policy ID
11388 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
11389 } else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
11390 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
11391 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
11392 // See necp_get_skip_policy_id_from_packet() and
11393 // necp_packet_should_skip_filters().
11394 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11395 } else {
11396 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11397 }
11398
11399 if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
11400 ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
11401 m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
11402 }
11403
11404 return 0;
11405 }
11406
11407 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)11408 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
11409 {
11410 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11411 return EINVAL;
11412 }
11413
11414 // Mark ID for Pass and IP Tunnel
11415 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
11416 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
11417 } else {
11418 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11419 }
11420
11421 return 0;
11422 }
11423
11424 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)11425 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
11426 {
11427 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11428 return EINVAL;
11429 }
11430
11431 // Mark ID for Pass and IP Tunnel
11432 if (interface != NULL) {
11433 packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
11434 }
11435
11436 return 0;
11437 }
11438
11439 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)11440 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
11441 {
11442 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11443 return EINVAL;
11444 }
11445
11446 if (is_keepalive) {
11447 packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
11448 } else {
11449 packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
11450 }
11451
11452 return 0;
11453 }
11454
11455 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)11456 necp_get_policy_id_from_packet(struct mbuf *packet)
11457 {
11458 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11459 return NECP_KERNEL_POLICY_ID_NONE;
11460 }
11461
11462 return packet->m_pkthdr.necp_mtag.necp_policy_id;
11463 }
11464
11465 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)11466 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
11467 {
11468 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11469 return NECP_KERNEL_POLICY_ID_NONE;
11470 }
11471
11472 // Check for overloaded value. See necp_mark_packet_from_socket().
11473 if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
11474 return NECP_KERNEL_POLICY_ID_NONE;
11475 }
11476
11477 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
11478 }
11479
11480 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)11481 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
11482 {
11483 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11484 return 0;
11485 }
11486
11487 return m_pftag(packet)->pftag_tag;
11488 }
11489
11490 bool
necp_packet_should_skip_filters(struct mbuf * packet)11491 necp_packet_should_skip_filters(struct mbuf *packet)
11492 {
11493 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11494 return false;
11495 }
11496
11497 // Check for overloaded value. See necp_mark_packet_from_socket().
11498 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
11499 }
11500
11501 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)11502 necp_get_last_interface_index_from_packet(struct mbuf *packet)
11503 {
11504 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11505 return 0;
11506 }
11507
11508 return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
11509 }
11510
11511 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)11512 necp_get_route_rule_id_from_packet(struct mbuf *packet)
11513 {
11514 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11515 return 0;
11516 }
11517
11518 return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
11519 }
11520
11521 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)11522 necp_get_app_uuid_from_packet(struct mbuf *packet,
11523 uuid_t app_uuid)
11524 {
11525 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11526 return EINVAL;
11527 }
11528
11529 bool found_mapping = FALSE;
11530 if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
11531 lck_rw_lock_shared(&necp_kernel_policy_lock);
11532 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);
11533 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
11534 if (entry != NULL) {
11535 uuid_copy(app_uuid, entry->uuid);
11536 found_mapping = true;
11537 }
11538 lck_rw_done(&necp_kernel_policy_lock);
11539 }
11540 if (!found_mapping) {
11541 uuid_clear(app_uuid);
11542 }
11543 return 0;
11544 }
11545
11546 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)11547 necp_get_is_keepalive_from_packet(struct mbuf *packet)
11548 {
11549 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
11550 return FALSE;
11551 }
11552
11553 return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
11554 }
11555
11556 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)11557 necp_socket_get_content_filter_control_unit(struct socket *so)
11558 {
11559 struct inpcb *inp = sotoinpcb(so);
11560
11561 if (inp == NULL) {
11562 return 0;
11563 }
11564 return inp->inp_policyresult.results.filter_control_unit;
11565 }
11566
11567 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)11568 necp_socket_should_use_flow_divert(struct inpcb *inp)
11569 {
11570 if (inp == NULL) {
11571 return FALSE;
11572 }
11573
11574 return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
11575 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11576 (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
11577 }
11578
11579 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)11580 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
11581 {
11582 if (inp == NULL) {
11583 return 0;
11584 }
11585
11586 if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
11587 return 0;
11588 }
11589
11590 if (aggregate_unit != NULL &&
11591 inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
11592 *aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
11593 }
11594
11595 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
11596 return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
11597 }
11598
11599 return 0;
11600 }
11601
11602 bool
necp_socket_should_rescope(struct inpcb * inp)11603 necp_socket_should_rescope(struct inpcb *inp)
11604 {
11605 if (inp == NULL) {
11606 return FALSE;
11607 }
11608
11609 return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
11610 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
11611 }
11612
11613 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)11614 necp_socket_get_rescope_if_index(struct inpcb *inp)
11615 {
11616 if (inp == NULL) {
11617 return 0;
11618 }
11619
11620 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
11621 return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
11622 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
11623 return necp_get_primary_direct_interface_index();
11624 }
11625
11626 return 0;
11627 }
11628
11629 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)11630 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
11631 {
11632 if (inp == NULL) {
11633 return current_mtu;
11634 }
11635
11636 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
11637 (inp->inp_flags & INP_BOUND_IF) &&
11638 inp->inp_boundifp) {
11639 u_int bound_interface_index = inp->inp_boundifp->if_index;
11640 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
11641
11642 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
11643 if (bound_interface_index != tunnel_interface_index) {
11644 ifnet_t tunnel_interface = NULL;
11645
11646 ifnet_head_lock_shared();
11647 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
11648 ifnet_head_done();
11649
11650 if (tunnel_interface != NULL) {
11651 u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
11652 u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
11653 if (delegate_tunnel_mtu != 0 &&
11654 strncmp(tunnel_interface->if_name, "ipsec", strlen("ipsec")) == 0) {
11655 // For ipsec interfaces, calculate the overhead from the delegate interface
11656 u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
11657 if (delegate_tunnel_mtu > tunnel_overhead) {
11658 delegate_tunnel_mtu -= tunnel_overhead;
11659 }
11660
11661 if (delegate_tunnel_mtu < direct_tunnel_mtu) {
11662 // If the (delegate - overhead) < direct, return (delegate - overhead)
11663 return delegate_tunnel_mtu;
11664 } else {
11665 // Otherwise return direct
11666 return direct_tunnel_mtu;
11667 }
11668 } else {
11669 // For non-ipsec interfaces, just return the tunnel MTU
11670 return direct_tunnel_mtu;
11671 }
11672 }
11673 }
11674 }
11675
11676 // By default, just return the MTU passed in
11677 return current_mtu;
11678 }
11679
11680 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)11681 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
11682 {
11683 if (result_parameter == NULL) {
11684 return NULL;
11685 }
11686
11687 return ifindex2ifnet[result_parameter->tunnel_interface_index];
11688 }
11689
11690 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)11691 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
11692 {
11693 bool found_match = FALSE;
11694 bool can_rebind = FALSE;
11695 ifaddr_t ifa;
11696 union necp_sockaddr_union address_storage;
11697
11698 if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
11699 return FALSE;
11700 }
11701
11702 // Match source address against interface addresses
11703 ifnet_lock_shared(interface);
11704 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
11705 if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
11706 if (address_storage.sa.sa_family != family) {
11707 continue;
11708 }
11709
11710 if (family == AF_INET) {
11711 struct ip *ip = mtod(packet, struct ip *);
11712 if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
11713 found_match = TRUE;
11714 break;
11715 }
11716 } else if (family == AF_INET6) {
11717 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
11718 if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
11719 found_match = TRUE;
11720 break;
11721 }
11722 }
11723 }
11724 }
11725 const uint32_t if_idx = interface->if_index;
11726 ifnet_lock_done(interface);
11727
11728 // If source address matched, attempt to construct a route to the destination address
11729 if (found_match) {
11730 ROUTE_RELEASE(new_route);
11731
11732 if (family == AF_INET) {
11733 struct ip *ip = mtod(packet, struct ip *);
11734 struct sockaddr_in *dst4 = (struct sockaddr_in *)(void *)&new_route->ro_dst;
11735 dst4->sin_family = AF_INET;
11736 dst4->sin_len = sizeof(struct sockaddr_in);
11737 dst4->sin_addr = ip->ip_dst;
11738 rtalloc_scoped(new_route, if_idx);
11739 if (!ROUTE_UNUSABLE(new_route)) {
11740 can_rebind = TRUE;
11741 }
11742 } else if (family == AF_INET6) {
11743 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
11744 struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)(void *)&new_route->ro_dst;
11745 dst6->sin6_family = AF_INET6;
11746 dst6->sin6_len = sizeof(struct sockaddr_in6);
11747 dst6->sin6_addr = ip6->ip6_dst;
11748 rtalloc_scoped(new_route, if_idx);
11749 if (!ROUTE_UNUSABLE(new_route)) {
11750 can_rebind = TRUE;
11751 }
11752 }
11753 }
11754
11755 return can_rebind;
11756 }
11757
11758 static bool
necp_addr_is_loopback(struct sockaddr * address)11759 necp_addr_is_loopback(struct sockaddr *address)
11760 {
11761 if (address == NULL) {
11762 return FALSE;
11763 }
11764
11765 if (address->sa_family == AF_INET) {
11766 return ntohl(((struct sockaddr_in *)(void *)address)->sin_addr.s_addr) == INADDR_LOOPBACK;
11767 } else if (address->sa_family == AF_INET6) {
11768 return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)(void *)address)->sin6_addr);
11769 }
11770
11771 return FALSE;
11772 }
11773
11774 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)11775 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
11776 {
11777 // Note: This function only checks for the loopback addresses.
11778 // In the future, we may want to expand to also allow any traffic
11779 // going through the loopback interface, but until then, this
11780 // check is cheaper.
11781
11782 if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
11783 return TRUE;
11784 }
11785
11786 if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
11787 return TRUE;
11788 }
11789
11790 if (inp != NULL) {
11791 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
11792 return TRUE;
11793 }
11794 if (inp->inp_vflag & INP_IPV4) {
11795 if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
11796 ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
11797 return TRUE;
11798 }
11799 } else if (inp->inp_vflag & INP_IPV6) {
11800 if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
11801 IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
11802 return TRUE;
11803 }
11804 }
11805 } else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
11806 return TRUE;
11807 }
11808
11809 if (packet != NULL) {
11810 struct ip *ip = mtod(packet, struct ip *);
11811 if (ip->ip_v == 4) {
11812 if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
11813 return TRUE;
11814 }
11815 if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
11816 return TRUE;
11817 }
11818 } else if (ip->ip_v == 6) {
11819 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
11820 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
11821 return TRUE;
11822 }
11823 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
11824 return TRUE;
11825 }
11826 }
11827 }
11828
11829 return FALSE;
11830 }
11831
11832 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)11833 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
11834 {
11835 if (inp != NULL) {
11836 if (!(inp->inp_vflag & INP_IPV6)) {
11837 return false;
11838 }
11839 if (INP_INTCOPROC_ALLOWED(inp)) {
11840 return true;
11841 }
11842 if ((inp->inp_flags & INP_BOUND_IF) &&
11843 IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
11844 return true;
11845 }
11846 return false;
11847 }
11848 if (packet != NULL) {
11849 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
11850 struct in6_addr *addrv6 = &ip6->ip6_dst;
11851 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
11852 NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
11853 return true;
11854 }
11855 }
11856
11857 return false;
11858 }
11859
11860 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)11861 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
11862 {
11863 char dest_str[MAX_IPv6_STR_LEN];
11864
11865 if (necp_drop_dest_debug > 0) {
11866 if (sau->sa.sa_family == AF_INET) {
11867 (void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
11868 } else if (sau->sa.sa_family == AF_INET6) {
11869 (void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
11870 } else {
11871 dest_str[0] = 0;
11872 }
11873 }
11874 for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
11875 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
11876 struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
11877
11878 if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
11879 if (necp_drop_dest_debug > 0) {
11880 char subnet_str[MAX_IPv6_STR_LEN];
11881 struct proc *p = current_proc();
11882 pid_t pid = proc_pid(p);
11883
11884 if (sau->sa.sa_family == AF_INET) {
11885 (void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
11886 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);
11887 } else if (sau->sa.sa_family == AF_INET6) {
11888 (void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
11889 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);
11890 }
11891 }
11892 return true;
11893 }
11894 }
11895 if (necp_drop_dest_debug > 1) {
11896 struct proc *p = current_proc();
11897 pid_t pid = proc_pid(p);
11898
11899 os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
11900 }
11901 return false;
11902 }
11903
11904 static int
11905 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
11906 {
11907 #pragma unused(arg1, arg2, oidp)
11908 int changed = 0;
11909 int error = 0;
11910 struct necp_drop_dest_policy tmp_drop_dest_policy;
11911 struct proc *p = current_proc();
11912 pid_t pid = proc_pid(p);
11913
11914 if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
11915 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
11916 NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
11917 return EPERM;
11918 }
11919 if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
11920 NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
11921 return EINVAL;
11922 }
11923
11924 memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
11925 error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
11926 if (error != 0) {
11927 NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
11928 return error;
11929 }
11930 if (changed == 0 || req->newptr == USER_ADDR_NULL) {
11931 return error;
11932 }
11933
11934 //
11935 // Validate the passed parameters
11936 //
11937 if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
11938 NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
11939 return EINVAL;
11940 }
11941 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
11942 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
11943 struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
11944
11945 switch (tmp_drop_dest_entry->level) {
11946 case NECP_SESSION_PRIORITY_UNKNOWN:
11947 if (tmp_drop_dest_policy.entry_count != 0) {
11948 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);
11949 return EINVAL;
11950 }
11951 break;
11952 case NECP_SESSION_PRIORITY_CONTROL:
11953 case NECP_SESSION_PRIORITY_CONTROL_1:
11954 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
11955 case NECP_SESSION_PRIORITY_HIGH:
11956 case NECP_SESSION_PRIORITY_HIGH_1:
11957 case NECP_SESSION_PRIORITY_HIGH_2:
11958 case NECP_SESSION_PRIORITY_HIGH_3:
11959 case NECP_SESSION_PRIORITY_HIGH_4:
11960 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
11961 case NECP_SESSION_PRIORITY_DEFAULT:
11962 case NECP_SESSION_PRIORITY_LOW:
11963 if (tmp_drop_dest_policy.entry_count == 0) {
11964 NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
11965 return EINVAL;
11966 }
11967 break;
11968 default: {
11969 NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
11970 return EINVAL;
11971 }
11972 }
11973
11974 switch (npca->address.sa.sa_family) {
11975 case AF_INET: {
11976 if (npca->prefix > 32) {
11977 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
11978 return EINVAL;
11979 }
11980 if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
11981 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
11982 return EINVAL;
11983 }
11984 if (npca->address.sin.sin_port != 0) {
11985 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);
11986 return EINVAL;
11987 }
11988 break;
11989 }
11990 case AF_INET6: {
11991 if (npca->prefix > 128) {
11992 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
11993 return EINVAL;
11994 }
11995 if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
11996 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
11997 return EINVAL;
11998 }
11999 if (npca->address.sin6.sin6_port != 0) {
12000 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);
12001 return EINVAL;
12002 }
12003 if (npca->address.sin6.sin6_flowinfo != 0) {
12004 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);
12005 return EINVAL;
12006 }
12007 if (npca->address.sin6.sin6_scope_id != 0) {
12008 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);
12009 return EINVAL;
12010 }
12011 break;
12012 }
12013 default: {
12014 return EINVAL;
12015 }
12016 }
12017 }
12018
12019 //
12020 // Commit the changed policy
12021 //
12022 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
12023 memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
12024
12025 necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
12026 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
12027 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
12028 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
12029
12030 memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
12031
12032 necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
12033 }
12034 lck_rw_done(&necp_kernel_policy_lock);
12035
12036 return 0;
12037 }
12038