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