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