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