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