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