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