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