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