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