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