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