Coverage Report

Created: 2026-07-10 06:42

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