]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/necp.c
xnu-2782.1.97.tar.gz
[apple/xnu.git] / bsd / net / necp.c
1 /*
2 * Copyright (c) 2013-2014 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/syslog.h>
33 #include <sys/queue.h>
34 #include <sys/malloc.h>
35 #include <libkern/OSMalloc.h>
36 #include <sys/kernel.h>
37 #include <sys/kern_control.h>
38 #include <sys/mbuf.h>
39 #include <sys/kpi_mbuf.h>
40 #include <sys/proc_uuid_policy.h>
41 #include <net/if.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <netinet/ip.h>
46 #include <netinet/ip6.h>
47 #include <netinet/tcp.h>
48 #include <netinet/udp.h>
49 #include <netinet/in_pcb.h>
50 #include <net/flowhash.h>
51 #include <net/if_var.h>
52 #include <sys/kauth.h>
53 #include <sys/sysctl.h>
54 #include <sys/sysproto.h>
55 #include <sys/priv.h>
56 #include <net/necp.h>
57
58 /*
59 * NECP - Network Extension Control Policy database
60 * ------------------------------------------------
61 * The goal of this module is to allow clients connecting via a
62 * kernel control socket to create high-level policy sessions, which
63 * are ingested into low-level kernel policies that control and tag
64 * traffic at the application, socket, and IP layers.
65 *
66 * ------------------------------------------------
67 * Sessions
68 * ------------------------------------------------
69 * Each session owns a list of session policies, each of which can
70 * specify any combination of conditions and a single result. Each
71 * session also has a priority level (such as High, Default, or Low)
72 * which is requested by the client. Based on the requested level,
73 * a session order value is assigned to the session, which will be used
74 * to sort kernel policies generated by the session. The session client
75 * can specify the sub-order for each policy it creates which will be
76 * used to further sort the kernel policies.
77 *
78 * Kernel Control Socket --> 1 necp_session --> list of necp_session_policy structs
79 *
80 * ------------------------------------------------
81 * Kernel Policies
82 * ------------------------------------------------
83 * Whenever a session send the Apply command, its policies are ingested
84 * and generate kernel policies. There are two phases of kernel policy
85 * ingestion.
86 *
87 * 1. The session policy is parsed to create kernel policies at the socket
88 * and IP layers, when applicable. For example, a policy that requires
89 * all traffic from App1 to Pass will generate a socket kernel policy to
90 * match App1 and mark packets with ID1, and also an IP policy to match
91 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
92 * resulting kernel policies are added to the global socket and IP layer
93 * policy lists.
94 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
95 * || ||
96 * \/ \/
97 * necp_kernel_socket_policies necp_kernel_ip_output_policies
98 *
99 * 2. Once the global lists of kernel policies have been filled out, each
100 * list is traversed to create optimized sub-lists ("Maps") which are used during
101 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
102 * which hashes incoming packets based on marked socket-layer policies, and removes
103 * duplicate or overlapping polcies. Socket policies are sent into two maps,
104 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
105 * The app layer map is used for policy checks coming in from user space, and is one
106 * list with duplicate and overlapping policies removed. The socket map hashes based
107 * on app UUID, and removes duplicate and overlapping policies.
108 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
109 * |-> necp_kernel_socket_policies_map
110 *
111 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
112 *
113 * ------------------------------------------------
114 * Drop All Level
115 * ------------------------------------------------
116 * The Drop All Level is a sysctl that controls the level at which policies are allowed
117 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
118 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
119 * by a session with a priority level better than (numerically less than) the
120 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
121 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
122 * session orders to be dropped.
123 */
124
125 u_int32_t necp_drop_all_order = 0;
126 u_int32_t necp_drop_all_level = 0;
127
128 u_int32_t necp_pass_loopback = 1; // 0=Off, 1=On
129 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
130
131 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
132
133 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
134
135 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
136 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
137 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
138 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
139 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", "");
140
141 #define NECPLOG(level, format, ...) do { \
142 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
143 } while (0)
144
145 #define NECPLOG0(level, msg) do { \
146 log((level > LOG_NOTICE ? LOG_NOTICE : level), "%s: %s\n", __FUNCTION__, msg); \
147 } while (0)
148
149 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
150 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
151 LIST_INSERT_HEAD((head), elm, field); \
152 } else { \
153 LIST_FOREACH(tmpelm, head, field) { \
154 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
155 LIST_INSERT_AFTER(tmpelm, elm, field); \
156 break; \
157 } \
158 } \
159 } \
160 } while (0)
161
162 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
163 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
164 LIST_INSERT_HEAD((head), elm, field); \
165 } else { \
166 LIST_FOREACH(tmpelm, head, field) { \
167 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))) { \
168 LIST_INSERT_AFTER(tmpelm, elm, field); \
169 break; \
170 } \
171 } \
172 } \
173 } while (0)
174
175 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
176 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))) { \
177 LIST_INSERT_HEAD((head), elm, field); \
178 } else { \
179 LIST_FOREACH(tmpelm, head, field) { \
180 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))) { \
181 LIST_INSERT_AFTER(tmpelm, elm, field); \
182 break; \
183 } \
184 } \
185 } \
186 } while (0)
187
188 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x00001
189 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x00002
190 #define NECP_KERNEL_CONDITION_PROTOCOL 0x00004
191 #define NECP_KERNEL_CONDITION_LOCAL_START 0x00008
192 #define NECP_KERNEL_CONDITION_LOCAL_END 0x00010
193 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x00020
194 #define NECP_KERNEL_CONDITION_REMOTE_START 0x00040
195 #define NECP_KERNEL_CONDITION_REMOTE_END 0x00080
196 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x00100
197 #define NECP_KERNEL_CONDITION_APP_ID 0x00200
198 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x00400
199 #define NECP_KERNEL_CONDITION_DOMAIN 0x00800
200 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x01000
201 #define NECP_KERNEL_CONDITION_POLICY_ID 0x02000
202 #define NECP_KERNEL_CONDITION_PID 0x04000
203 #define NECP_KERNEL_CONDITION_UID 0x08000
204 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x10000 // Only set from packets looping between interfaces
205 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x20000
206 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x40000
207
208 struct necp_service_registration {
209 LIST_ENTRY(necp_service_registration) session_chain;
210 LIST_ENTRY(necp_service_registration) kernel_chain;
211 u_int32_t service_id;
212 };
213
214 struct necp_session {
215 u_int32_t control_unit;
216 u_int32_t session_priority; // Descriptive priority rating
217 u_int32_t session_order;
218
219 bool proc_locked; // Messages must come from proc_uuid
220 uuid_t proc_uuid;
221
222 bool dirty;
223 LIST_HEAD(_policies, necp_session_policy) policies;
224
225 LIST_HEAD(_services, necp_service_registration) services;
226 };
227
228 struct necp_socket_info {
229 pid_t pid;
230 uid_t uid;
231 union necp_sockaddr_union local_addr;
232 union necp_sockaddr_union remote_addr;
233 u_int32_t bound_interface_index;
234 u_int32_t traffic_class;
235 u_int16_t protocol;
236 u_int32_t application_id;
237 u_int32_t real_application_id;
238 u_int32_t account_id;
239 char *domain;
240 errno_t cred_result;
241 };
242
243 static kern_ctl_ref necp_kctlref;
244 static u_int32_t necp_family;
245 static OSMallocTag necp_malloc_tag;
246 static lck_grp_attr_t *necp_kernel_policy_grp_attr = NULL;
247 static lck_attr_t *necp_kernel_policy_mtx_attr = NULL;
248 static lck_grp_t *necp_kernel_policy_mtx_grp = NULL;
249 decl_lck_rw_data(static, necp_kernel_policy_lock);
250
251 static necp_policy_id necp_last_policy_id = 0;
252 static necp_kernel_policy_id necp_last_kernel_policy_id = 0;
253 static u_int32_t necp_last_uuid_id = 0;
254 static u_int32_t necp_last_string_id = 0;
255
256 /*
257 * On modification, invalidate cached lookups by bumping the generation count.
258 * Other calls will need to take the slowpath of taking
259 * the subsystem lock.
260 */
261 static volatile int32_t necp_kernel_socket_policies_gencount;
262 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
263 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
264 necp_kernel_socket_policies_gencount = 1; \
265 } \
266 } while (0)
267
268 static u_int32_t necp_kernel_application_policies_condition_mask;
269 static size_t necp_kernel_application_policies_count;
270 static u_int32_t necp_kernel_socket_policies_condition_mask;
271 static size_t necp_kernel_socket_policies_count;
272 static size_t necp_kernel_socket_policies_non_app_count;
273 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
274 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
275 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
276 static struct necp_kernel_socket_policy **necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
277 static struct necp_kernel_socket_policy **necp_kernel_socket_policies_app_layer_map;
278 /*
279 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
280 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
281 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
282 *
283 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
284 */
285
286 static u_int32_t necp_kernel_ip_output_policies_condition_mask;
287 static size_t necp_kernel_ip_output_policies_count;
288 static size_t necp_kernel_ip_output_policies_non_id_count;
289 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
290 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
291 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
292 static struct necp_kernel_ip_output_policy **necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
293
294 static struct necp_session *necp_create_session(u_int32_t control_unit);
295 static void necp_delete_session(struct necp_session *session);
296
297 static void necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
298 static void necp_handle_policy_get(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
299 static void necp_handle_policy_delete(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
300 static void necp_handle_policy_apply_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
301 static void necp_handle_policy_list_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
302 static void necp_handle_policy_delete_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
303 static void necp_handle_set_session_priority(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
304 static void necp_handle_lock_session_to_proc(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
305 static void necp_handle_register_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
306 static void necp_handle_unregister_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset);
307
308 static struct necp_session_policy *necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *conditions_array, size_t conditions_array_size, u_int8_t *result, size_t result_size);
309 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
310 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
311 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
312 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
313 static void necp_policy_apply_all(struct necp_session *session);
314
315 static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_id parent_policy_id, necp_policy_order order, u_int32_t session_order, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, u_int32_t cond_account_id, char *domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
316 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
317 static bool necp_kernel_socket_policies_reprocess(void);
318 static bool necp_kernel_socket_policies_update_uuid_table(void);
319 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, necp_kernel_policy_result *return_service_action, necp_kernel_policy_service *return_service);
320
321 static necp_kernel_policy_id necp_kernel_ip_output_policy_add(necp_policy_id parent_policy_id, necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, 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, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
322 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
323 static bool necp_kernel_ip_output_policies_reprocess(void);
324
325 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
326 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);
327 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
328 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
329 static bool necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits);
330 static bool necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet);
331
332 struct necp_uuid_id_mapping {
333 LIST_ENTRY(necp_uuid_id_mapping) chain;
334 uuid_t uuid;
335 u_int32_t id;
336 u_int32_t refcount;
337 u_int32_t table_refcount; // Add to UUID policy table count
338 };
339 static size_t necp_num_uuid_app_id_mappings;
340 static bool necp_uuid_app_id_mappings_dirty;
341 #define NECP_UUID_APP_ID_HASH_SIZE 64
342 static u_long necp_uuid_app_id_hash_mask;
343 static u_long necp_uuid_app_id_hash_num_buckets;
344 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
345 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
346 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
347 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
348
349 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
350 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
351 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
352 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
353
354 struct necp_string_id_mapping {
355 LIST_ENTRY(necp_string_id_mapping) chain;
356 char *string;
357 necp_app_id id;
358 u_int32_t refcount;
359 };
360 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
361 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
362 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
363
364 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
365
366 static char *necp_create_trimmed_domain(char *string, size_t length);
367 static inline int necp_count_dots(char *string, size_t length);
368
369 // Session order allocation
370 static u_int32_t
371 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
372 {
373 u_int32_t new_order = 0;
374
375 // For now, just allocate 1000 orders for each priority
376 if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
377 priority = NECP_SESSION_PRIORITY_DEFAULT;
378 }
379
380 // Use the control unit to decide the offset into the priority list
381 new_order = (control_unit) + ((priority - 1) * 1000);
382
383 return (new_order);
384 }
385
386 static inline u_int32_t
387 necp_get_first_order_for_priority(u_int32_t priority)
388 {
389 return (((priority - 1) * 1000) + 1);
390 }
391
392 // Sysctl handler
393 static int
394 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
395 {
396 #pragma unused(arg1, arg2)
397 int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
398 if (necp_drop_all_level == 0) {
399 necp_drop_all_order = 0;
400 } else {
401 necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
402 }
403 return (error);
404 }
405
406
407 // Kernel Control functions
408 static errno_t necp_register_control(void);
409 static errno_t necp_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo);
410 static errno_t necp_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo);
411 static errno_t necp_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t m, int flags);
412 static void necp_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags);
413 static errno_t necp_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len);
414 static errno_t necp_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len);
415
416 static bool necp_send_ctl_data(struct necp_session *session, u_int8_t *buffer, size_t buffer_size);
417
418 errno_t
419 necp_init(void)
420 {
421 errno_t result = 0;
422
423 result = necp_register_control();
424 if (result != 0) {
425 goto done;
426 }
427
428 necp_kernel_policy_grp_attr = lck_grp_attr_alloc_init();
429 if (necp_kernel_policy_grp_attr == NULL) {
430 NECPLOG0(LOG_ERR, "lck_grp_attr_alloc_init failed");
431 result = ENOMEM;
432 goto done;
433 }
434
435 necp_kernel_policy_mtx_grp = lck_grp_alloc_init(NECP_CONTROL_NAME, necp_kernel_policy_grp_attr);
436 if (necp_kernel_policy_mtx_grp == NULL) {
437 NECPLOG0(LOG_ERR, "lck_grp_alloc_init failed");
438 result = ENOMEM;
439 goto done;
440 }
441
442 necp_kernel_policy_mtx_attr = lck_attr_alloc_init();
443 if (necp_kernel_policy_mtx_attr == NULL) {
444 NECPLOG0(LOG_ERR, "lck_attr_alloc_init failed");
445 result = ENOMEM;
446 goto done;
447 }
448
449 lck_rw_init(&necp_kernel_policy_lock, necp_kernel_policy_mtx_grp, necp_kernel_policy_mtx_attr);
450
451 LIST_INIT(&necp_kernel_socket_policies);
452 LIST_INIT(&necp_kernel_ip_output_policies);
453
454 LIST_INIT(&necp_account_id_list);
455
456 LIST_INIT(&necp_uuid_service_id_list);
457
458 LIST_INIT(&necp_registered_service_list);
459
460 necp_uuid_app_id_hashtbl = hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask);
461 necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
462 necp_num_uuid_app_id_mappings = 0;
463 necp_uuid_app_id_mappings_dirty = FALSE;
464
465 necp_kernel_application_policies_condition_mask = 0;
466 necp_kernel_socket_policies_condition_mask = 0;
467 necp_kernel_ip_output_policies_condition_mask = 0;
468
469 necp_kernel_application_policies_count = 0;
470 necp_kernel_socket_policies_count = 0;
471 necp_kernel_socket_policies_non_app_count = 0;
472 necp_kernel_ip_output_policies_count = 0;
473 necp_kernel_ip_output_policies_non_id_count = 0;
474
475 necp_last_policy_id = 0;
476 necp_last_kernel_policy_id = 0;
477
478 necp_kernel_socket_policies_gencount = 1;
479
480 memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
481 memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
482 necp_kernel_socket_policies_app_layer_map = NULL;
483
484 done:
485 if (result != 0) {
486 if (necp_kernel_policy_mtx_attr != NULL) {
487 lck_attr_free(necp_kernel_policy_mtx_attr);
488 necp_kernel_policy_mtx_attr = NULL;
489 }
490 if (necp_kernel_policy_mtx_grp != NULL) {
491 lck_grp_free(necp_kernel_policy_mtx_grp);
492 necp_kernel_policy_mtx_grp = NULL;
493 }
494 if (necp_kernel_policy_grp_attr != NULL) {
495 lck_grp_attr_free(necp_kernel_policy_grp_attr);
496 necp_kernel_policy_grp_attr = NULL;
497 }
498 if (necp_kctlref != NULL) {
499 ctl_deregister(necp_kctlref);
500 necp_kctlref = NULL;
501 }
502 }
503 return (result);
504 }
505
506 static errno_t
507 necp_register_control(void)
508 {
509 struct kern_ctl_reg kern_ctl;
510 errno_t result = 0;
511
512 // Create a tag to allocate memory
513 necp_malloc_tag = OSMalloc_Tagalloc(NECP_CONTROL_NAME, OSMT_DEFAULT);
514
515 // Find a unique value for our interface family
516 result = mbuf_tag_id_find(NECP_CONTROL_NAME, &necp_family);
517 if (result != 0) {
518 NECPLOG(LOG_ERR, "mbuf_tag_id_find_internal failed: %d", result);
519 return (result);
520 }
521
522 bzero(&kern_ctl, sizeof(kern_ctl));
523 strlcpy(kern_ctl.ctl_name, NECP_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
524 kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
525 kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; // Require root
526 kern_ctl.ctl_sendsize = 64 * 1024;
527 kern_ctl.ctl_recvsize = 64 * 1024;
528 kern_ctl.ctl_connect = necp_ctl_connect;
529 kern_ctl.ctl_disconnect = necp_ctl_disconnect;
530 kern_ctl.ctl_send = necp_ctl_send;
531 kern_ctl.ctl_rcvd = necp_ctl_rcvd;
532 kern_ctl.ctl_setopt = necp_ctl_setopt;
533 kern_ctl.ctl_getopt = necp_ctl_getopt;
534
535 result = ctl_register(&kern_ctl, &necp_kctlref);
536 if (result != 0) {
537 NECPLOG(LOG_ERR, "ctl_register failed: %d", result);
538 return (result);
539 }
540
541 return (0);
542 }
543
544 static errno_t
545 necp_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
546 {
547 #pragma unused(kctlref)
548 *unitinfo = necp_create_session(sac->sc_unit);
549 if (*unitinfo == NULL) {
550 // Could not allocate session
551 return (ENOBUFS);
552 }
553
554 return (0);
555 }
556
557 static errno_t
558 necp_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo)
559 {
560 #pragma unused(kctlref, unit)
561 struct necp_session *session = (struct necp_session *)unitinfo;
562 if (session != NULL) {
563 necp_policy_mark_all_for_deletion(session);
564 necp_policy_apply_all(session);
565 necp_delete_session((struct necp_session *)unitinfo);
566 }
567
568 return (0);
569 }
570
571
572 // Message handling
573 static int
574 necp_packet_find_tlv(mbuf_t packet, int offset, u_int8_t type, int *err, int next)
575 {
576 size_t cursor = offset;
577 int error = 0;
578 size_t curr_length;
579 u_int8_t curr_type;
580
581 *err = 0;
582
583 do {
584 if (!next) {
585 error = mbuf_copydata(packet, cursor, sizeof(curr_type), &curr_type);
586 if (error) {
587 *err = ENOENT;
588 return (-1);
589 }
590 } else {
591 next = 0;
592 curr_type = NECP_TLV_NIL;
593 }
594
595 if (curr_type != type) {
596 cursor += sizeof(curr_type);
597 error = mbuf_copydata(packet, cursor, sizeof(curr_length), &curr_length);
598 if (error) {
599 *err = error;
600 return (-1);
601 }
602 cursor += (sizeof(curr_length) + curr_length);
603 }
604 } while (curr_type != type);
605
606 return (cursor);
607 }
608
609 static int
610 necp_packet_get_tlv_at_offset(mbuf_t packet, int tlv_offset, size_t buff_len, void *buff, size_t *value_size)
611 {
612 int error = 0;
613 size_t length;
614
615 if (tlv_offset < 0) {
616 return (error);
617 }
618
619 error = mbuf_copydata(packet, tlv_offset + sizeof(u_int8_t), sizeof(length), &length);
620 if (error) {
621 return (error);
622 }
623
624 if (value_size != NULL) {
625 *value_size = length;
626 }
627
628 if (buff != NULL && buff_len > 0) {
629 size_t to_copy = (length < buff_len) ? length : buff_len;
630 error = mbuf_copydata(packet, tlv_offset + sizeof(u_int8_t) + sizeof(length), to_copy, buff);
631 if (error) {
632 return (error);
633 }
634 }
635
636 return (0);
637 }
638
639 static int
640 necp_packet_get_tlv(mbuf_t packet, int offset, u_int8_t type, size_t buff_len, void *buff, size_t *value_size)
641 {
642 int error = 0;
643 int tlv_offset;
644
645 tlv_offset = necp_packet_find_tlv(packet, offset, type, &error, 0);
646 if (tlv_offset < 0) {
647 return (error);
648 }
649
650 return (necp_packet_get_tlv_at_offset(packet, tlv_offset, buff_len, buff, value_size));
651 }
652
653 static u_int8_t *
654 necp_buffer_write_packet_header(u_int8_t *buffer, u_int8_t packet_type, u_int8_t flags, u_int32_t message_id)
655 {
656 ((struct necp_packet_header *)(void *)buffer)->packet_type = packet_type;
657 ((struct necp_packet_header *)(void *)buffer)->flags = flags;
658 ((struct necp_packet_header *)(void *)buffer)->message_id = message_id;
659 return (buffer + sizeof(struct necp_packet_header));
660 }
661
662 static u_int8_t *
663 necp_buffer_write_tlv(u_int8_t *buffer, u_int8_t type, size_t length, const void *value)
664 {
665 *(u_int8_t *)(buffer) = type;
666 *(size_t *)(void *)(buffer + sizeof(type)) = length;
667 if (length > 0) {
668 memcpy((u_int8_t *)(buffer + sizeof(type) + sizeof(length)), value, length);
669 }
670
671 return ((u_int8_t *)(buffer + sizeof(type) + sizeof(length) + length));
672 }
673
674 static u_int8_t
675 necp_buffer_get_tlv_type(u_int8_t *buffer, int tlv_offset)
676 {
677 u_int8_t *type = NULL;
678
679 if (buffer == NULL) {
680 return (0);
681 }
682
683 type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
684 return (type ? *type : 0);
685 }
686
687 static size_t
688 necp_buffer_get_tlv_length(u_int8_t *buffer, int tlv_offset)
689 {
690 size_t *length = NULL;
691
692 if (buffer == NULL) {
693 return (0);
694 }
695
696 length = (size_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
697 return (length ? *length : 0);
698 }
699
700 static u_int8_t *
701 necp_buffer_get_tlv_value(u_int8_t *buffer, int tlv_offset, size_t *value_size)
702 {
703 u_int8_t *value = NULL;
704 size_t length = necp_buffer_get_tlv_length(buffer, tlv_offset);
705 if (length == 0) {
706 return (value);
707 }
708
709 if (value_size) {
710 *value_size = length;
711 }
712
713 value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(size_t));
714 return (value);
715 }
716
717 static int
718 necp_buffer_find_tlv(u_int8_t *buffer, size_t buffer_length, int offset, u_int8_t type, int next)
719 {
720 size_t cursor = offset;
721 size_t curr_length;
722 u_int8_t curr_type;
723
724 do {
725 if (cursor >= buffer_length) {
726 return (-1);
727 }
728 if (!next) {
729 curr_type = necp_buffer_get_tlv_type(buffer, cursor);
730 } else {
731 next = 0;
732 curr_type = NECP_TLV_NIL;
733 }
734 if (curr_type != type) {
735 curr_length = necp_buffer_get_tlv_length(buffer, cursor);
736 cursor += (sizeof(curr_type) + sizeof(curr_length) + curr_length);
737 }
738 } while (curr_type != type);
739
740 return (cursor);
741 }
742
743 static bool
744 necp_send_ctl_data(struct necp_session *session, u_int8_t *buffer, size_t buffer_size)
745 {
746 int error;
747
748 if (necp_kctlref == NULL || session == NULL || buffer == NULL || buffer_size == 0) {
749 return (FALSE);
750 }
751
752 error = ctl_enqueuedata(necp_kctlref, session->control_unit, buffer, buffer_size, CTL_DATA_EOR);
753
754 return (error == 0);
755 }
756
757 static bool
758 necp_send_success_response(struct necp_session *session, u_int8_t packet_type, u_int32_t message_id)
759 {
760 bool success = TRUE;
761 u_int8_t *response = NULL;
762 u_int8_t *cursor = NULL;
763 size_t response_size = sizeof(struct necp_packet_header) + sizeof(u_int8_t) + sizeof(size_t);
764 MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
765 if (response == NULL) {
766 return (FALSE);
767 }
768 cursor = response;
769 cursor = necp_buffer_write_packet_header(cursor, packet_type, NECP_PACKET_FLAGS_RESPONSE, message_id);
770 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_NIL, 0, NULL);
771
772 if (!(success = necp_send_ctl_data(session, (u_int8_t *)response, response_size))) {
773 NECPLOG0(LOG_ERR, "Failed to send response");
774 }
775
776 FREE(response, M_NECP);
777 return (success);
778 }
779
780 static bool
781 necp_send_error_response(struct necp_session *session, u_int8_t packet_type, u_int32_t message_id, u_int32_t error)
782 {
783 bool success = TRUE;
784 u_int8_t *response = NULL;
785 u_int8_t *cursor = NULL;
786 size_t response_size = sizeof(struct necp_packet_header) + sizeof(u_int8_t) + sizeof(size_t) + sizeof(u_int32_t);
787 MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
788 if (response == NULL) {
789 return (FALSE);
790 }
791 cursor = response;
792 cursor = necp_buffer_write_packet_header(cursor, packet_type, NECP_PACKET_FLAGS_RESPONSE, message_id);
793 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ERROR, sizeof(error), &error);
794
795 if (!(success = necp_send_ctl_data(session, (u_int8_t *)response, response_size))) {
796 NECPLOG0(LOG_ERR, "Failed to send response");
797 }
798
799 FREE(response, M_NECP);
800 return (success);
801 }
802
803 static bool
804 necp_send_policy_id_response(struct necp_session *session, u_int8_t packet_type, u_int32_t message_id, necp_policy_id policy_id)
805 {
806 bool success = TRUE;
807 u_int8_t *response = NULL;
808 u_int8_t *cursor = NULL;
809 size_t response_size = sizeof(struct necp_packet_header) + sizeof(u_int8_t) + sizeof(size_t) + sizeof(u_int32_t);
810 MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
811 if (response == NULL) {
812 return (FALSE);
813 }
814 cursor = response;
815 cursor = necp_buffer_write_packet_header(cursor, packet_type, NECP_PACKET_FLAGS_RESPONSE, message_id);
816 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy_id), &policy_id);
817
818 if (!(success = necp_send_ctl_data(session, (u_int8_t *)response, response_size))) {
819 NECPLOG0(LOG_ERR, "Failed to send response");
820 }
821
822 FREE(response, M_NECP);
823 return (success);
824 }
825
826 static errno_t
827 necp_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t packet, int flags)
828 {
829 #pragma unused(kctlref, unit, flags)
830 struct necp_session *session = (struct necp_session *)unitinfo;
831 struct necp_packet_header header;
832 int error = 0;
833
834 if (session == NULL) {
835 NECPLOG0(LOG_ERR, "Got a NULL session");
836 error = EINVAL;
837 goto done;
838 }
839
840 if (mbuf_pkthdr_len(packet) < sizeof(header)) {
841 NECPLOG(LOG_ERR, "Got a bad packet, length (%lu) < sizeof header (%lu)", mbuf_pkthdr_len(packet), sizeof(header));
842 error = EINVAL;
843 goto done;
844 }
845
846 error = mbuf_copydata(packet, 0, sizeof(header), &header);
847 if (error) {
848 NECPLOG(LOG_ERR, "mbuf_copydata failed for the header: %d", error);
849 error = ENOBUFS;
850 goto done;
851 }
852
853 if (session->proc_locked) {
854 // Verify that the calling process is allowed to send messages
855 uuid_t proc_uuid;
856 proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
857 if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
858 necp_send_error_response(session, header.packet_type, header.message_id, NECP_ERROR_INVALID_PROCESS);
859 goto done;
860 }
861 }
862
863 switch (header.packet_type) {
864 case NECP_PACKET_TYPE_POLICY_ADD: {
865 necp_handle_policy_add(session, header.message_id, packet, sizeof(header));
866 break;
867 }
868 case NECP_PACKET_TYPE_POLICY_GET: {
869 necp_handle_policy_get(session, header.message_id, packet, sizeof(header));
870 break;
871 }
872 case NECP_PACKET_TYPE_POLICY_DELETE: {
873 necp_handle_policy_delete(session, header.message_id, packet, sizeof(header));
874 break;
875 }
876 case NECP_PACKET_TYPE_POLICY_APPLY_ALL: {
877 necp_handle_policy_apply_all(session, header.message_id, packet, sizeof(header));
878 break;
879 }
880 case NECP_PACKET_TYPE_POLICY_LIST_ALL: {
881 necp_handle_policy_list_all(session, header.message_id, packet, sizeof(header));
882 break;
883 }
884 case NECP_PACKET_TYPE_POLICY_DELETE_ALL: {
885 necp_handle_policy_delete_all(session, header.message_id, packet, sizeof(header));
886 break;
887 }
888 case NECP_PACKET_TYPE_SET_SESSION_PRIORITY: {
889 necp_handle_set_session_priority(session, header.message_id, packet, sizeof(header));
890 break;
891 }
892 case NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC: {
893 necp_handle_lock_session_to_proc(session, header.message_id, packet, sizeof(header));
894 break;
895 }
896 case NECP_PACKET_TYPE_REGISTER_SERVICE: {
897 necp_handle_register_service(session, header.message_id, packet, sizeof(header));
898 break;
899 }
900 case NECP_PACKET_TYPE_UNREGISTER_SERVICE: {
901 necp_handle_unregister_service(session, header.message_id, packet, sizeof(header));
902 break;
903 }
904 default: {
905 NECPLOG(LOG_ERR, "Received unknown message type %d", header.packet_type);
906 necp_send_error_response(session, header.packet_type, header.message_id, NECP_ERROR_UNKNOWN_PACKET_TYPE);
907 break;
908 }
909 }
910
911 done:
912 mbuf_freem(packet);
913 return (error);
914 }
915
916 static void
917 necp_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags)
918 {
919 #pragma unused(kctlref, unit, unitinfo, flags)
920 return;
921 }
922
923 static errno_t
924 necp_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len)
925 {
926 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
927 return (0);
928 }
929
930 static errno_t
931 necp_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len)
932 {
933 #pragma unused(kctlref, unit, unitinfo, opt, data, len)
934 return (0);
935 }
936
937 // Session Management
938 static struct necp_session *
939 necp_create_session(u_int32_t control_unit)
940 {
941 struct necp_session *new_session = NULL;
942
943 MALLOC(new_session, struct necp_session *, sizeof(*new_session), M_NECP, M_WAITOK);
944 if (new_session == NULL) {
945 goto done;
946 }
947 if (necp_debug) {
948 NECPLOG(LOG_DEBUG, "Create NECP session, control unit %d", control_unit);
949 }
950 memset(new_session, 0, sizeof(*new_session));
951 new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
952 new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
953 new_session->control_unit = control_unit;
954 new_session->dirty = FALSE;
955 LIST_INIT(&new_session->policies);
956
957 done:
958 return (new_session);
959 }
960
961 static void
962 necp_delete_session(struct necp_session *session)
963 {
964 if (session != NULL) {
965 struct necp_service_registration *service = NULL;
966 struct necp_service_registration *temp_service = NULL;
967 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
968 LIST_REMOVE(service, session_chain);
969 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
970 LIST_REMOVE(service, kernel_chain);
971 lck_rw_done(&necp_kernel_policy_lock);
972 FREE(service, M_NECP);
973 }
974 if (necp_debug) {
975 NECPLOG0(LOG_DEBUG, "Deleted NECP session");
976 }
977 FREE(session, M_NECP);
978 }
979 }
980
981 // Session Policy Management
982 static inline u_int8_t
983 necp_policy_result_get_type_from_buffer(u_int8_t *buffer, size_t length)
984 {
985 return ((buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0);
986 }
987
988 static inline size_t
989 necp_policy_result_get_parameter_length_from_buffer(u_int8_t *buffer, size_t length)
990 {
991 return ((buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0);
992 }
993
994 static inline u_int8_t *
995 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t *buffer, size_t length)
996 {
997 return ((buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL);
998 }
999
1000 static bool
1001 necp_policy_result_is_valid(u_int8_t *buffer, size_t length)
1002 {
1003 bool validated = FALSE;
1004 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
1005 size_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
1006 switch (type) {
1007 case NECP_POLICY_RESULT_PASS: {
1008 validated = TRUE;
1009 break;
1010 }
1011 case NECP_POLICY_RESULT_SKIP: {
1012 if (parameter_length >= sizeof(u_int32_t)) {
1013 validated = TRUE;
1014 }
1015 break;
1016 }
1017 case NECP_POLICY_RESULT_DROP: {
1018 validated = TRUE;
1019 break;
1020 }
1021 case NECP_POLICY_RESULT_SOCKET_DIVERT: {
1022 if (parameter_length >= sizeof(u_int32_t)) {
1023 validated = TRUE;
1024 }
1025 break;
1026 }
1027 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
1028 if (parameter_length > 0) {
1029 validated = TRUE;
1030 }
1031 break;
1032 }
1033 case NECP_POLICY_RESULT_IP_TUNNEL: {
1034 if (parameter_length > sizeof(u_int32_t)) {
1035 validated = TRUE;
1036 }
1037 break;
1038 }
1039 case NECP_POLICY_RESULT_SOCKET_FILTER: {
1040 if (parameter_length >= sizeof(u_int32_t)) {
1041 validated = TRUE;
1042 }
1043 break;
1044 }
1045 case NECP_POLICY_RESULT_TRIGGER:
1046 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED:
1047 case NECP_POLICY_RESULT_TRIGGER_SCOPED:
1048 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED: {
1049 if (parameter_length >= sizeof(uuid_t)) {
1050 validated = TRUE;
1051 }
1052 break;
1053 }
1054 default: {
1055 validated = FALSE;
1056 break;
1057 }
1058 }
1059
1060 if (necp_debug) {
1061 NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
1062 }
1063
1064 return (validated);
1065 }
1066
1067 static inline u_int8_t
1068 necp_policy_condition_get_type_from_buffer(u_int8_t *buffer, size_t length)
1069 {
1070 return ((buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0);
1071 }
1072
1073 static inline u_int8_t
1074 necp_policy_condition_get_flags_from_buffer(u_int8_t *buffer, size_t length)
1075 {
1076 return ((buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0);
1077 }
1078
1079 static inline size_t
1080 necp_policy_condition_get_value_length_from_buffer(u_int8_t *buffer, size_t length)
1081 {
1082 return ((buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0);
1083 }
1084
1085 static inline u_int8_t *
1086 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t *buffer, size_t length)
1087 {
1088 return ((buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL);
1089 }
1090
1091 static inline bool
1092 necp_policy_condition_is_default(u_int8_t *buffer, size_t length)
1093 {
1094 return (necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT);
1095 }
1096
1097 static inline bool
1098 necp_policy_condition_is_application(u_int8_t *buffer, size_t length)
1099 {
1100 return (necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION);
1101 }
1102
1103 static inline bool
1104 necp_policy_condition_requires_application(u_int8_t *buffer, size_t length)
1105 {
1106 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
1107 return (type == NECP_POLICY_CONDITION_REAL_APPLICATION ||
1108 type == NECP_POLICY_CONDITION_ENTITLEMENT);
1109 }
1110
1111 static bool
1112 necp_policy_condition_is_valid(u_int8_t *buffer, size_t length, u_int8_t policy_result_type)
1113 {
1114 bool validated = FALSE;
1115 bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
1116 policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
1117 policy_result_type == NECP_POLICY_RESULT_TRIGGER ||
1118 policy_result_type == NECP_POLICY_RESULT_TRIGGER_IF_NEEDED ||
1119 policy_result_type == NECP_POLICY_RESULT_TRIGGER_SCOPED ||
1120 policy_result_type == NECP_POLICY_RESULT_NO_TRIGGER_SCOPED ||
1121 policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED) ? TRUE : FALSE;
1122 size_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
1123 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
1124 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
1125 u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
1126 switch (type) {
1127 case NECP_POLICY_CONDITION_APPLICATION:
1128 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
1129 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
1130 condition_length >= sizeof(uuid_t) &&
1131 condition_value != NULL &&
1132 !uuid_is_null(condition_value)) {
1133 validated = TRUE;
1134 }
1135 break;
1136 }
1137 case NECP_POLICY_CONDITION_DOMAIN:
1138 case NECP_POLICY_CONDITION_ACCOUNT:
1139 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
1140 if (condition_length > 0) {
1141 validated = TRUE;
1142 }
1143 break;
1144 }
1145 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
1146 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
1147 validated = TRUE;
1148 }
1149 break;
1150 }
1151 case NECP_POLICY_CONDITION_DEFAULT:
1152 case NECP_POLICY_CONDITION_ALL_INTERFACES:
1153 case NECP_POLICY_CONDITION_ENTITLEMENT: {
1154 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
1155 validated = TRUE;
1156 }
1157 break;
1158 }
1159 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
1160 if (condition_length >= sizeof(u_int16_t)) {
1161 validated = TRUE;
1162 }
1163 break;
1164 }
1165 case NECP_POLICY_CONDITION_PID: {
1166 if (condition_length >= sizeof(pid_t) &&
1167 condition_value != NULL &&
1168 *((pid_t *)(void *)condition_value) != 0) {
1169 validated = TRUE;
1170 }
1171 break;
1172 }
1173 case NECP_POLICY_CONDITION_UID: {
1174 if (condition_length >= sizeof(uid_t)) {
1175 validated = TRUE;
1176 }
1177 break;
1178 }
1179 case NECP_POLICY_CONDITION_LOCAL_ADDR:
1180 case NECP_POLICY_CONDITION_REMOTE_ADDR: {
1181 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr)) {
1182 validated = TRUE;
1183 }
1184 break;
1185 }
1186 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
1187 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
1188 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range)) {
1189 validated = TRUE;
1190 }
1191 break;
1192 }
1193 default: {
1194 validated = FALSE;
1195 break;
1196 }
1197 }
1198
1199 if (necp_debug) {
1200 NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
1201 }
1202
1203 return (validated);
1204 }
1205
1206 static void
1207 necp_handle_set_session_priority(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1208 {
1209 int error;
1210 struct necp_session_policy *policy = NULL;
1211 struct necp_session_policy *temp_policy = NULL;
1212 u_int32_t response_error = NECP_ERROR_INTERNAL;
1213 u_int32_t requested_session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
1214
1215 // Read policy id
1216 error = necp_packet_get_tlv(packet, offset, NECP_TLV_SESSION_PRIORITY, sizeof(requested_session_priority), &requested_session_priority, NULL);
1217 if (error) {
1218 NECPLOG(LOG_ERR, "Failed to get session priority: %d", error);
1219 response_error = NECP_ERROR_INVALID_TLV;
1220 goto fail;
1221 }
1222
1223 if (session == NULL) {
1224 NECPLOG0(LOG_ERR, "Failed to find session");
1225 response_error = NECP_ERROR_INTERNAL;
1226 goto fail;
1227 }
1228
1229 // Enforce special session priorities with entitlements
1230 if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1231 requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL) {
1232 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1233 if (cred_result != 0) {
1234 NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1235 goto fail;
1236 }
1237 }
1238
1239 if (session->session_priority != requested_session_priority) {
1240 session->session_priority = requested_session_priority;
1241 session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1242 session->dirty = TRUE;
1243
1244 // Mark all policies as needing updates
1245 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1246 policy->pending_update = TRUE;
1247 }
1248 }
1249
1250 necp_send_success_response(session, NECP_PACKET_TYPE_SET_SESSION_PRIORITY, message_id);
1251 return;
1252
1253 fail:
1254 necp_send_error_response(session, NECP_PACKET_TYPE_SET_SESSION_PRIORITY, message_id, response_error);
1255 }
1256
1257 static void
1258 necp_handle_lock_session_to_proc(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1259 {
1260 #pragma unused(packet, offset)
1261 proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1262 session->proc_locked = TRUE;
1263 necp_send_success_response(session, NECP_PACKET_TYPE_LOCK_SESSION_TO_PROC, message_id);
1264 }
1265
1266 static void
1267 necp_handle_register_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1268 {
1269 int error;
1270 struct necp_service_registration *new_service = NULL;
1271 u_int32_t response_error = NECP_ERROR_INTERNAL;
1272 uuid_t service_uuid;
1273 uuid_clear(service_uuid);
1274
1275 if (session == NULL) {
1276 NECPLOG0(LOG_ERR, "Failed to find session");
1277 response_error = NECP_ERROR_INTERNAL;
1278 goto fail;
1279 }
1280
1281 // Enforce entitlements
1282 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1283 if (cred_result != 0) {
1284 NECPLOG0(LOG_ERR, "Session does not hold necessary entitlement to register service");
1285 goto fail;
1286 }
1287
1288 // Read service uuid
1289 error = necp_packet_get_tlv(packet, offset, NECP_TLV_SERVICE_UUID, sizeof(uuid_t), service_uuid, NULL);
1290 if (error) {
1291 NECPLOG(LOG_ERR, "Failed to get service UUID: %d", error);
1292 response_error = NECP_ERROR_INVALID_TLV;
1293 goto fail;
1294 }
1295
1296 MALLOC(new_service, struct necp_service_registration *, sizeof(*new_service), M_NECP, M_WAITOK);
1297 if (new_service == NULL) {
1298 NECPLOG0(LOG_ERR, "Failed to allocate service registration");
1299 response_error = NECP_ERROR_INTERNAL;
1300 goto fail;
1301 }
1302
1303 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1304 memset(new_service, 0, sizeof(*new_service));
1305 new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1306 LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1307 LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1308 lck_rw_done(&necp_kernel_policy_lock);
1309
1310 necp_send_success_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id);
1311 return;
1312 fail:
1313 necp_send_error_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id, response_error);
1314 }
1315
1316 static void
1317 necp_handle_unregister_service(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1318 {
1319 int error;
1320 struct necp_service_registration *service = NULL;
1321 struct necp_service_registration *temp_service = NULL;
1322 u_int32_t response_error = NECP_ERROR_INTERNAL;
1323 struct necp_uuid_id_mapping *mapping = NULL;
1324 uuid_t service_uuid;
1325 uuid_clear(service_uuid);
1326
1327 if (session == NULL) {
1328 NECPLOG0(LOG_ERR, "Failed to find session");
1329 response_error = NECP_ERROR_INTERNAL;
1330 goto fail;
1331 }
1332
1333 // Read service uuid
1334 error = necp_packet_get_tlv(packet, offset, NECP_TLV_SERVICE_UUID, sizeof(uuid_t), service_uuid, NULL);
1335 if (error) {
1336 NECPLOG(LOG_ERR, "Failed to get service UUID: %d", error);
1337 response_error = NECP_ERROR_INVALID_TLV;
1338 goto fail;
1339 }
1340
1341 // Mark remove all matching services for this session
1342 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1343 mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1344 if (mapping != NULL) {
1345 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1346 if (service->service_id == mapping->id) {
1347 LIST_REMOVE(service, session_chain);
1348 LIST_REMOVE(service, kernel_chain);
1349 FREE(service, M_NECP);
1350 }
1351 }
1352 necp_remove_uuid_service_id_mapping(service_uuid);
1353 }
1354 lck_rw_done(&necp_kernel_policy_lock);
1355
1356 necp_send_success_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id);
1357 return;
1358 fail:
1359 necp_send_error_response(session, NECP_PACKET_TYPE_REGISTER_SERVICE, message_id, response_error);
1360 }
1361
1362 static void
1363 necp_handle_policy_add(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1364 {
1365 bool has_default_condition = FALSE;
1366 bool has_non_default_condition = FALSE;
1367 bool has_application_condition = FALSE;
1368 bool requires_application_condition = FALSE;
1369 u_int8_t *conditions_array = NULL;
1370 size_t conditions_array_size = 0;
1371 int conditions_array_cursor;
1372
1373 int cursor;
1374 int error = 0;
1375 u_int32_t response_error = NECP_ERROR_INTERNAL;
1376
1377 necp_policy_order order = 0;
1378 struct necp_session_policy *policy = NULL;
1379 u_int8_t *policy_result = NULL;
1380 size_t policy_result_size = 0;
1381
1382 // Read policy order
1383 error = necp_packet_get_tlv(packet, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
1384 if (error) {
1385 NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
1386 response_error = NECP_ERROR_INVALID_TLV;
1387 goto fail;
1388 }
1389
1390 // Read policy result
1391 cursor = necp_packet_find_tlv(packet, offset, NECP_TLV_POLICY_RESULT, &error, 0);
1392 error = necp_packet_get_tlv_at_offset(packet, cursor, 0, NULL, &policy_result_size);
1393 if (error || policy_result_size == 0) {
1394 NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
1395 response_error = NECP_ERROR_INVALID_TLV;
1396 goto fail;
1397 }
1398 MALLOC(policy_result, u_int8_t *, policy_result_size, M_NECP, M_WAITOK);
1399 if (policy_result == NULL) {
1400 NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
1401 response_error = NECP_ERROR_INTERNAL;
1402 goto fail;
1403 }
1404 error = necp_packet_get_tlv_at_offset(packet, cursor, policy_result_size, policy_result, NULL);
1405 if (error) {
1406 NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
1407 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
1408 goto fail;
1409 }
1410 if (!necp_policy_result_is_valid(policy_result, policy_result_size)) {
1411 NECPLOG0(LOG_ERR, "Failed to validate policy result");
1412 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
1413 goto fail;
1414 }
1415
1416 // Read policy conditions
1417 for (cursor = necp_packet_find_tlv(packet, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
1418 cursor >= 0;
1419 cursor = necp_packet_find_tlv(packet, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
1420 size_t condition_size = 0;
1421 necp_packet_get_tlv_at_offset(packet, cursor, 0, NULL, &condition_size);
1422
1423 if (condition_size > 0) {
1424 conditions_array_size += (sizeof(u_int8_t) + sizeof(size_t) + condition_size);
1425 }
1426 }
1427
1428 if (conditions_array_size == 0) {
1429 NECPLOG0(LOG_ERR, "Failed to get policy conditions");
1430 response_error = NECP_ERROR_INVALID_TLV;
1431 goto fail;
1432 }
1433 MALLOC(conditions_array, u_int8_t *, conditions_array_size, M_NECP, M_WAITOK);
1434 if (conditions_array == NULL) {
1435 NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
1436 response_error = NECP_ERROR_INTERNAL;
1437 goto fail;
1438 }
1439
1440 conditions_array_cursor = 0;
1441 for (cursor = necp_packet_find_tlv(packet, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
1442 cursor >= 0;
1443 cursor = necp_packet_find_tlv(packet, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
1444 u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
1445 size_t condition_size = 0;
1446 necp_packet_get_tlv_at_offset(packet, cursor, 0, NULL, &condition_size);
1447 if (condition_size > 0 && condition_size <= (conditions_array_size - conditions_array_cursor)) {
1448 // Add type
1449 memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
1450 conditions_array_cursor += sizeof(condition_type);
1451
1452 // Add length
1453 memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
1454 conditions_array_cursor += sizeof(condition_size);
1455
1456 // Add value
1457 necp_packet_get_tlv_at_offset(packet, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
1458 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))) {
1459 NECPLOG0(LOG_ERR, "Failed to validate policy condition");
1460 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
1461 goto fail;
1462 }
1463
1464 if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
1465 has_default_condition = TRUE;
1466 } else {
1467 has_non_default_condition = TRUE;
1468 }
1469 if (has_default_condition && has_non_default_condition) {
1470 NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
1471 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
1472 goto fail;
1473 }
1474
1475 if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
1476 has_application_condition = TRUE;
1477 }
1478
1479 if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
1480 requires_application_condition = TRUE;
1481 }
1482
1483 conditions_array_cursor += condition_size;
1484 }
1485 }
1486
1487 if (requires_application_condition && !has_application_condition) {
1488 NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
1489 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
1490 goto fail;
1491 }
1492
1493 if ((policy = necp_policy_create(session, order, conditions_array, conditions_array_size, policy_result, policy_result_size)) == NULL) {
1494 response_error = NECP_ERROR_INTERNAL;
1495 goto fail;
1496 }
1497
1498 necp_send_policy_id_response(session, NECP_PACKET_TYPE_POLICY_ADD, message_id, policy->id);
1499 return;
1500
1501 fail:
1502 if (policy_result != NULL) {
1503 FREE(policy_result, M_NECP);
1504 }
1505 if (conditions_array != NULL) {
1506 FREE(conditions_array, M_NECP);
1507 }
1508
1509 necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_ADD, message_id, response_error);
1510 }
1511
1512 static void
1513 necp_handle_policy_get(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1514 {
1515 #pragma unused(offset)
1516 int error;
1517 u_int8_t *response = NULL;
1518 u_int8_t *cursor = NULL;
1519 u_int32_t response_error = NECP_ERROR_INTERNAL;
1520 necp_policy_id policy_id = 0;
1521 size_t order_tlv_size = 0;
1522 size_t result_tlv_size = 0;
1523 size_t response_size = 0;
1524
1525 struct necp_session_policy *policy = NULL;
1526
1527 // Read policy id
1528 error = necp_packet_get_tlv(packet, offset, NECP_TLV_POLICY_ID, sizeof(policy_id), &policy_id, NULL);
1529 if (error) {
1530 NECPLOG(LOG_ERR, "Failed to get policy id: %d", error);
1531 response_error = NECP_ERROR_INVALID_TLV;
1532 goto fail;
1533 }
1534
1535 policy = necp_policy_find(session, policy_id);
1536 if (policy == NULL || policy->pending_deletion) {
1537 NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1538 response_error = NECP_ERROR_POLICY_ID_NOT_FOUND;
1539 goto fail;
1540 }
1541
1542 order_tlv_size = sizeof(u_int8_t) + sizeof(size_t) + sizeof(necp_policy_order);
1543 result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(size_t) + policy->result_size) : 0);
1544 response_size = sizeof(struct necp_packet_header) + order_tlv_size + result_tlv_size + policy->conditions_size;
1545 MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
1546 if (response == NULL) {
1547 necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_LIST_ALL, message_id, NECP_ERROR_INTERNAL);
1548 return;
1549 }
1550
1551 cursor = response;
1552 cursor = necp_buffer_write_packet_header(cursor, NECP_PACKET_TYPE_POLICY_GET, NECP_PACKET_FLAGS_RESPONSE, message_id);
1553 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order);
1554
1555 if (result_tlv_size) {
1556 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, &policy->result);
1557 }
1558 if (policy->conditions_size) {
1559 memcpy(((u_int8_t *)(void *)(cursor)), policy->conditions, policy->conditions_size);
1560 }
1561
1562 if (!necp_send_ctl_data(session, (u_int8_t *)response, response_size)) {
1563 NECPLOG0(LOG_ERR, "Failed to send response");
1564 }
1565
1566 FREE(response, M_NECP);
1567 return;
1568
1569 fail:
1570 necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_GET, message_id, response_error);
1571 }
1572
1573 static void
1574 necp_handle_policy_delete(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1575 {
1576 int error;
1577 u_int32_t response_error = NECP_ERROR_INTERNAL;
1578 necp_policy_id policy_id = 0;
1579
1580 struct necp_session_policy *policy = NULL;
1581
1582 // Read policy id
1583 error = necp_packet_get_tlv(packet, offset, NECP_TLV_POLICY_ID, sizeof(policy_id), &policy_id, NULL);
1584 if (error) {
1585 NECPLOG(LOG_ERR, "Failed to get policy id: %d", error);
1586 response_error = NECP_ERROR_INVALID_TLV;
1587 goto fail;
1588 }
1589
1590 policy = necp_policy_find(session, policy_id);
1591 if (policy == NULL || policy->pending_deletion) {
1592 NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1593 response_error = NECP_ERROR_POLICY_ID_NOT_FOUND;
1594 goto fail;
1595 }
1596
1597 necp_policy_mark_for_deletion(session, policy);
1598
1599 necp_send_success_response(session, NECP_PACKET_TYPE_POLICY_DELETE, message_id);
1600 return;
1601
1602 fail:
1603 necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_DELETE, message_id, response_error);
1604 }
1605
1606 static void
1607 necp_handle_policy_apply_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1608 {
1609 #pragma unused(packet, offset)
1610 necp_policy_apply_all(session);
1611 necp_send_success_response(session, NECP_PACKET_TYPE_POLICY_APPLY_ALL, message_id);
1612 }
1613
1614 static void
1615 necp_handle_policy_list_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1616 {
1617 #pragma unused(packet, offset)
1618 size_t tlv_size = (sizeof(u_int8_t) + sizeof(size_t) + sizeof(u_int32_t));
1619 size_t response_size = 0;
1620 u_int8_t *response = NULL;
1621 u_int8_t *cursor = NULL;
1622 int num_policies = 0;
1623 int cur_policy_index = 0;
1624 struct necp_session_policy *policy;
1625
1626 LIST_FOREACH(policy, &session->policies, chain) {
1627 if (!policy->pending_deletion) {
1628 num_policies++;
1629 }
1630 }
1631
1632 // Create a response with one Policy ID TLV for each policy
1633 response_size = sizeof(struct necp_packet_header) + num_policies * tlv_size;
1634 MALLOC(response, u_int8_t *, response_size, M_NECP, M_WAITOK);
1635 if (response == NULL) {
1636 necp_send_error_response(session, NECP_PACKET_TYPE_POLICY_LIST_ALL, message_id, NECP_ERROR_INTERNAL);
1637 return;
1638 }
1639
1640 cursor = response;
1641 cursor = necp_buffer_write_packet_header(cursor, NECP_PACKET_TYPE_POLICY_LIST_ALL, NECP_PACKET_FLAGS_RESPONSE, message_id);
1642
1643 LIST_FOREACH(policy, &session->policies, chain) {
1644 if (!policy->pending_deletion && cur_policy_index < num_policies) {
1645 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->id);
1646 cur_policy_index++;
1647 }
1648 }
1649
1650 if (!necp_send_ctl_data(session, (u_int8_t *)response, response_size)) {
1651 NECPLOG0(LOG_ERR, "Failed to send response");
1652 }
1653
1654 FREE(response, M_NECP);
1655 }
1656
1657 static void
1658 necp_handle_policy_delete_all(struct necp_session *session, u_int32_t message_id, mbuf_t packet, int offset)
1659 {
1660 #pragma unused(packet, offset)
1661 necp_policy_mark_all_for_deletion(session);
1662 necp_send_success_response(session, NECP_PACKET_TYPE_POLICY_DELETE_ALL, message_id);
1663 }
1664
1665 static necp_policy_id
1666 necp_policy_get_new_id(void)
1667 {
1668 necp_policy_id newid = 0;
1669
1670 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1671
1672 necp_last_policy_id++;
1673 if (necp_last_policy_id < 1) {
1674 necp_last_policy_id = 1;
1675 }
1676
1677 newid = necp_last_policy_id;
1678 lck_rw_done(&necp_kernel_policy_lock);
1679
1680 if (newid == 0) {
1681 NECPLOG0(LOG_DEBUG, "Allocate policy id failed.\n");
1682 return (0);
1683 }
1684
1685 return (newid);
1686 }
1687
1688 static struct necp_session_policy *
1689 necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *conditions_array, size_t conditions_array_size, u_int8_t *result, size_t result_size)
1690 {
1691 struct necp_session_policy *new_policy = NULL;
1692 struct necp_session_policy *tmp_policy = NULL;
1693
1694 if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
1695 goto done;
1696 }
1697
1698 MALLOC_ZONE(new_policy, struct necp_session_policy *, sizeof(*new_policy), M_NECP_SESSION_POLICY, M_WAITOK);
1699 if (new_policy == NULL) {
1700 goto done;
1701 }
1702
1703 memset(new_policy, 0, sizeof(*new_policy));
1704 new_policy->applied = FALSE;
1705 new_policy->pending_deletion = FALSE;
1706 new_policy->pending_update = FALSE;
1707 new_policy->order = order;
1708 new_policy->conditions = conditions_array;
1709 new_policy->conditions_size = conditions_array_size;
1710 new_policy->result = result;
1711 new_policy->result_size = result_size;
1712 new_policy->id = necp_policy_get_new_id();
1713
1714 LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
1715
1716 session->dirty = TRUE;
1717
1718 if (necp_debug) {
1719 NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
1720 }
1721 done:
1722 return (new_policy);
1723 }
1724
1725 static struct necp_session_policy *
1726 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
1727 {
1728 struct necp_session_policy *policy = NULL;
1729 if (policy_id == 0) {
1730 return (NULL);
1731 }
1732
1733 LIST_FOREACH(policy, &session->policies, chain) {
1734 if (policy->id == policy_id) {
1735 return (policy);
1736 }
1737 }
1738
1739 return (NULL);
1740 }
1741
1742 static inline u_int8_t
1743 necp_policy_get_result_type(struct necp_session_policy *policy)
1744 {
1745 return (policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0);
1746 }
1747
1748 static inline size_t
1749 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
1750 {
1751 return (policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0);
1752 }
1753
1754 static bool
1755 necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t *parameter_buffer, size_t parameter_buffer_length)
1756 {
1757 if (policy) {
1758 size_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
1759 if (parameter_buffer_length >= parameter_length) {
1760 u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
1761 if (parameter && parameter_buffer) {
1762 memcpy(parameter_buffer, parameter, parameter_length);
1763 return (TRUE);
1764 }
1765 }
1766 }
1767
1768 return (FALSE);
1769 }
1770
1771 static bool
1772 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
1773 {
1774 if (session == NULL || policy == NULL) {
1775 return (FALSE);
1776 }
1777
1778 policy->pending_deletion = TRUE;
1779 session->dirty = TRUE;
1780
1781 if (necp_debug) {
1782 NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
1783 }
1784 return (TRUE);
1785 }
1786
1787 static bool
1788 necp_policy_mark_all_for_deletion(struct necp_session *session)
1789 {
1790 struct necp_session_policy *policy = NULL;
1791 struct necp_session_policy *temp_policy = NULL;
1792
1793 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1794 necp_policy_mark_for_deletion(session, policy);
1795 }
1796
1797 return (TRUE);
1798 }
1799
1800 static bool
1801 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
1802 {
1803 if (session == NULL || policy == NULL) {
1804 return (FALSE);
1805 }
1806
1807 LIST_REMOVE(policy, chain);
1808
1809 if (policy->result) {
1810 FREE(policy->result, M_NECP);
1811 policy->result = NULL;
1812 }
1813
1814 if (policy->conditions) {
1815 FREE(policy->conditions, M_NECP);
1816 policy->conditions = NULL;
1817 }
1818
1819 FREE_ZONE(policy, sizeof(*policy), M_NECP_SESSION_POLICY);
1820
1821 if (necp_debug) {
1822 NECPLOG0(LOG_DEBUG, "Removed NECP policy");
1823 }
1824 return (TRUE);
1825 }
1826
1827 static bool
1828 necp_policy_unapply(struct necp_session_policy *policy)
1829 {
1830 int i = 0;
1831 if (policy == NULL) {
1832 return (FALSE);
1833 }
1834
1835 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
1836
1837 // Release local uuid mappings
1838 if (!uuid_is_null(policy->applied_app_uuid)) {
1839 bool removed_mapping = FALSE;
1840 if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
1841 necp_uuid_app_id_mappings_dirty = TRUE;
1842 necp_num_uuid_app_id_mappings--;
1843 }
1844 uuid_clear(policy->applied_app_uuid);
1845 }
1846 if (!uuid_is_null(policy->applied_real_app_uuid)) {
1847 necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
1848 uuid_clear(policy->applied_real_app_uuid);
1849 }
1850 if (!uuid_is_null(policy->applied_service_uuid)) {
1851 necp_remove_uuid_service_id_mapping(policy->applied_service_uuid);
1852 uuid_clear(policy->applied_service_uuid);
1853 }
1854
1855 // Release string mappings
1856 if (policy->applied_account != NULL) {
1857 necp_remove_string_to_id_mapping(&necp_account_id_list, policy->applied_account);
1858 FREE(policy->applied_account, M_NECP);
1859 policy->applied_account = NULL;
1860 }
1861
1862 // Remove socket policies
1863 for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
1864 if (policy->kernel_socket_policies[i] != 0) {
1865 necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
1866 policy->kernel_socket_policies[i] = 0;
1867 }
1868 }
1869
1870 // Remove IP output policies
1871 for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
1872 if (policy->kernel_ip_output_policies[i] != 0) {
1873 necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
1874 policy->kernel_ip_output_policies[i] = 0;
1875 }
1876 }
1877
1878 policy->applied = FALSE;
1879
1880 return (TRUE);
1881 }
1882
1883 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
1884 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
1885 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
1886 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
1887 struct necp_policy_result_ip_tunnel {
1888 u_int32_t secondary_result;
1889 char interface_name[IFXNAMSIZ];
1890 } __attribute__((__packed__));
1891
1892 struct necp_policy_result_service {
1893 uuid_t identifier;
1894 u_int32_t data;
1895 } __attribute__((__packed__));
1896
1897 static bool
1898 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
1899 {
1900 bool socket_only_conditions = FALSE;
1901 bool socket_ip_conditions = FALSE;
1902
1903 bool socket_layer_non_id_conditions = FALSE;
1904 bool ip_output_layer_non_id_conditions = FALSE;
1905 bool ip_output_layer_id_condition = FALSE;
1906 bool ip_output_layer_tunnel_condition_from_id = FALSE;
1907 bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
1908 necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
1909
1910 u_int32_t master_condition_mask = 0;
1911 u_int32_t master_condition_negated_mask = 0;
1912 ifnet_t cond_bound_interface = NULL;
1913 u_int32_t cond_account_id = 0;
1914 char *cond_domain = NULL;
1915 pid_t cond_pid = 0;
1916 uid_t cond_uid = 0;
1917 necp_app_id cond_app_id = 0;
1918 necp_app_id cond_real_app_id = 0;
1919 struct necp_policy_condition_tc_range cond_traffic_class;
1920 cond_traffic_class.start_tc = 0;
1921 cond_traffic_class.end_tc = 0;
1922 u_int16_t cond_protocol = 0;
1923 union necp_sockaddr_union cond_local_start;
1924 union necp_sockaddr_union cond_local_end;
1925 u_int8_t cond_local_prefix = 0;
1926 union necp_sockaddr_union cond_remote_start;
1927 union necp_sockaddr_union cond_remote_end;
1928 u_int8_t cond_remote_prefix = 0;
1929 size_t offset = 0;
1930 u_int8_t ultimate_result = 0;
1931 u_int32_t secondary_result = 0;
1932 necp_kernel_policy_result_parameter secondary_result_parameter;
1933 memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
1934 u_int32_t cond_last_interface_index = 0;
1935 necp_kernel_policy_result_parameter ultimate_result_parameter;
1936 memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
1937
1938 if (policy == NULL) {
1939 return (FALSE);
1940 }
1941
1942 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
1943
1944 // Process conditions
1945 while (offset < policy->conditions_size) {
1946 size_t length = 0;
1947 u_int8_t *value = necp_buffer_get_tlv_value(policy->conditions, offset, &length);
1948
1949 u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
1950 u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
1951 bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
1952 size_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
1953 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
1954 switch (condition_type) {
1955 case NECP_POLICY_CONDITION_DEFAULT: {
1956 socket_ip_conditions = TRUE;
1957 break;
1958 }
1959 case NECP_POLICY_CONDITION_ALL_INTERFACES: {
1960 master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
1961 socket_ip_conditions = TRUE;
1962 break;
1963 }
1964 case NECP_POLICY_CONDITION_ENTITLEMENT: {
1965 master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
1966 socket_only_conditions = TRUE;
1967 break;
1968 }
1969 case NECP_POLICY_CONDITION_DOMAIN: {
1970 // Make sure there is only one such rule
1971 if (condition_length > 0 && cond_domain == NULL) {
1972 cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
1973 if (cond_domain != NULL) {
1974 master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN;
1975 if (condition_is_negative) {
1976 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN;
1977 }
1978 socket_only_conditions = TRUE;
1979 }
1980 }
1981 break;
1982 }
1983 case NECP_POLICY_CONDITION_ACCOUNT: {
1984 // Make sure there is only one such rule
1985 if (condition_length > 0 && cond_account_id == 0 && policy->applied_account == NULL) {
1986 char *string = NULL;
1987 MALLOC(string, char *, condition_length + 1, M_NECP, M_WAITOK);
1988 if (string != NULL) {
1989 memcpy(string, condition_value, condition_length);
1990 string[condition_length] = 0;
1991 cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, string);
1992 if (cond_account_id != 0) {
1993 policy->applied_account = string; // Save the string in parent policy
1994 master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
1995 if (condition_is_negative) {
1996 master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
1997 }
1998 socket_only_conditions = TRUE;
1999 } else {
2000 FREE(string, M_NECP);
2001 }
2002 }
2003 }
2004 break;
2005 }
2006 case NECP_POLICY_CONDITION_APPLICATION: {
2007 // Make sure there is only one such rule, because we save the uuid in the policy
2008 if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
2009 bool allocated_mapping = FALSE;
2010 uuid_t application_uuid;
2011 memcpy(application_uuid, condition_value, sizeof(uuid_t));
2012 cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
2013 if (cond_app_id != 0) {
2014 if (allocated_mapping) {
2015 necp_uuid_app_id_mappings_dirty = TRUE;
2016 necp_num_uuid_app_id_mappings++;
2017 }
2018 uuid_copy(policy->applied_app_uuid, application_uuid);
2019 master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
2020 if (condition_is_negative) {
2021 master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
2022 }
2023 socket_only_conditions = TRUE;
2024 }
2025 }
2026 break;
2027 }
2028 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2029 // Make sure there is only one such rule, because we save the uuid in the policy
2030 if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
2031 uuid_t real_application_uuid;
2032 memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
2033 cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
2034 if (cond_real_app_id != 0) {
2035 uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
2036 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
2037 if (condition_is_negative) {
2038 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
2039 }
2040 socket_only_conditions = TRUE;
2041 }
2042 }
2043 break;
2044 }
2045 case NECP_POLICY_CONDITION_PID: {
2046 if (condition_length >= sizeof(pid_t)) {
2047 master_condition_mask |= NECP_KERNEL_CONDITION_PID;
2048 if (condition_is_negative) {
2049 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
2050 }
2051 memcpy(&cond_pid, condition_value, sizeof(cond_pid));
2052 socket_only_conditions = TRUE;
2053 }
2054 break;
2055 }
2056 case NECP_POLICY_CONDITION_UID: {
2057 if (condition_length >= sizeof(uid_t)) {
2058 master_condition_mask |= NECP_KERNEL_CONDITION_UID;
2059 if (condition_is_negative) {
2060 master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
2061 }
2062 memcpy(&cond_uid, condition_value, sizeof(cond_uid));
2063 socket_only_conditions = TRUE;
2064 }
2065 break;
2066 }
2067 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2068 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2069 master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
2070 if (condition_is_negative) {
2071 master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
2072 }
2073 memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
2074 socket_only_conditions = TRUE;
2075 }
2076 break;
2077 }
2078 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
2079 if (condition_length <= IFXNAMSIZ && condition_length > 0) {
2080 char interface_name[IFXNAMSIZ];
2081 memcpy(interface_name, condition_value, condition_length);
2082 interface_name[condition_length - 1] = 0; // Make sure the string is NULL terminated
2083 if (ifnet_find_by_name(interface_name, &cond_bound_interface) == 0) {
2084 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
2085 if (condition_is_negative) {
2086 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
2087 }
2088 }
2089 socket_ip_conditions = TRUE;
2090 }
2091 break;
2092 }
2093 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2094 if (condition_length >= sizeof(u_int16_t)) {
2095 master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
2096 if (condition_is_negative) {
2097 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
2098 }
2099 memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
2100 socket_ip_conditions = TRUE;
2101 }
2102 break;
2103 }
2104 case NECP_POLICY_CONDITION_LOCAL_ADDR: {
2105 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
2106 cond_local_prefix = address_struct->prefix;
2107 memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
2108 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
2109 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
2110 if (condition_is_negative) {
2111 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
2112 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
2113 }
2114 socket_ip_conditions = TRUE;
2115 break;
2116 }
2117 case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2118 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
2119 cond_remote_prefix = address_struct->prefix;
2120 memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
2121 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
2122 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
2123 if (condition_is_negative) {
2124 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
2125 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
2126 }
2127 socket_ip_conditions = TRUE;
2128 break;
2129 }
2130 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE: {
2131 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
2132 memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
2133 memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
2134 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
2135 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
2136 if (condition_is_negative) {
2137 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
2138 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
2139 }
2140 socket_ip_conditions = TRUE;
2141 break;
2142 }
2143 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2144 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
2145 memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
2146 memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
2147 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
2148 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
2149 if (condition_is_negative) {
2150 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
2151 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
2152 }
2153 socket_ip_conditions = TRUE;
2154 break;
2155 }
2156 default: {
2157 break;
2158 }
2159 }
2160
2161 offset += sizeof(u_int8_t) + sizeof(size_t) + length;
2162 }
2163
2164 // Process result
2165 ultimate_result = necp_policy_get_result_type(policy);
2166 switch (ultimate_result) {
2167 case NECP_POLICY_RESULT_PASS: {
2168 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
2169 socket_layer_non_id_conditions = TRUE;
2170 ip_output_layer_id_condition = TRUE;
2171 } else if (socket_ip_conditions) {
2172 socket_layer_non_id_conditions = TRUE;
2173 ip_output_layer_id_condition = TRUE;
2174 ip_output_layer_non_id_conditions = TRUE;
2175 }
2176 break;
2177 }
2178 case NECP_POLICY_RESULT_DROP: {
2179 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
2180 socket_layer_non_id_conditions = TRUE;
2181 } else if (socket_ip_conditions) {
2182 socket_layer_non_id_conditions = TRUE;
2183 ip_output_layer_non_id_conditions = TRUE;
2184 }
2185 break;
2186 }
2187 case NECP_POLICY_RESULT_SKIP: {
2188 u_int32_t skip_policy_order = 0;
2189 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
2190 ultimate_result_parameter.skip_policy_order = skip_policy_order;
2191 }
2192
2193 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
2194 socket_layer_non_id_conditions = TRUE;
2195 ip_output_layer_id_condition = TRUE;
2196 } else if (socket_ip_conditions) {
2197 socket_layer_non_id_conditions = TRUE;
2198 ip_output_layer_non_id_conditions = TRUE;
2199 }
2200 break;
2201 }
2202 case NECP_POLICY_RESULT_SOCKET_DIVERT:
2203 case NECP_POLICY_RESULT_SOCKET_FILTER: {
2204 u_int32_t control_unit = 0;
2205 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
2206 ultimate_result_parameter.flow_divert_control_unit = control_unit;
2207 }
2208 socket_layer_non_id_conditions = TRUE;
2209 break;
2210 }
2211 case NECP_POLICY_RESULT_IP_TUNNEL: {
2212 struct necp_policy_result_ip_tunnel tunnel_parameters;
2213 size_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
2214 if (tunnel_parameters_length > sizeof(u_int32_t) &&
2215 tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
2216 necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
2217 ifnet_t tunnel_interface = NULL;
2218 tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0; // Make sure the string is NULL terminated
2219 if (ifnet_find_by_name(tunnel_parameters.interface_name, &tunnel_interface) == 0) {
2220 ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
2221 }
2222
2223 secondary_result = tunnel_parameters.secondary_result;
2224 if (secondary_result) {
2225 cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
2226 }
2227 }
2228
2229 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
2230 socket_layer_non_id_conditions = TRUE;
2231 ip_output_layer_id_condition = TRUE;
2232 if (secondary_result) {
2233 ip_output_layer_tunnel_condition_from_id = TRUE;
2234 }
2235 } else if (socket_ip_conditions) {
2236 socket_layer_non_id_conditions = TRUE;
2237 ip_output_layer_id_condition = TRUE;
2238 ip_output_layer_non_id_conditions = TRUE;
2239 if (secondary_result) {
2240 ip_output_layer_tunnel_condition_from_id = TRUE;
2241 ip_output_layer_tunnel_condition_from_non_id = TRUE;
2242 }
2243 }
2244 break;
2245 }
2246 case NECP_POLICY_RESULT_TRIGGER:
2247 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED:
2248 case NECP_POLICY_RESULT_TRIGGER_SCOPED:
2249 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED: {
2250 struct necp_policy_result_service service_parameters;
2251 size_t service_result_length = necp_policy_get_result_parameter_length(policy);
2252 bool has_extra_service_data = FALSE;
2253 if (service_result_length >= (sizeof(service_parameters))) {
2254 has_extra_service_data = TRUE;
2255 }
2256 if (necp_policy_get_result_parameter(policy, (u_int8_t *)&service_parameters, sizeof(service_parameters))) {
2257 ultimate_result_parameter.service.identifier = necp_create_uuid_service_id_mapping(service_parameters.identifier);
2258 if (ultimate_result_parameter.service.identifier != 0) {
2259 uuid_copy(policy->applied_service_uuid, service_parameters.identifier);
2260 socket_layer_non_id_conditions = TRUE;
2261 if (has_extra_service_data) {
2262 ultimate_result_parameter.service.data = service_parameters.data;
2263 } else {
2264 ultimate_result_parameter.service.data = 0;
2265 }
2266 }
2267 }
2268 break;
2269 }
2270 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2271 size_t interface_name_length = necp_policy_get_result_parameter_length(policy);
2272 if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
2273 char interface_name[IFXNAMSIZ];
2274 ifnet_t scope_interface = NULL;
2275 necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
2276 interface_name[interface_name_length - 1] = 0; // Make sure the string is NULL terminated
2277 if (ifnet_find_by_name(interface_name, &scope_interface) == 0) {
2278 ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
2279 socket_layer_non_id_conditions = TRUE;
2280 }
2281 }
2282 }
2283 default: {
2284 break;
2285 }
2286 }
2287
2288 if (socket_layer_non_id_conditions) {
2289 necp_kernel_policy_id policy_id = necp_kernel_socket_policy_add(policy->id, policy->order, session->session_order, master_condition_mask, master_condition_negated_mask, cond_app_id, cond_real_app_id, cond_account_id, cond_domain, cond_pid, cond_uid, cond_bound_interface, cond_traffic_class, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, ultimate_result, ultimate_result_parameter);
2290
2291 if (policy_id == 0) {
2292 NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
2293 goto fail;
2294 }
2295
2296 cond_ip_output_layer_id = policy_id;
2297 policy->kernel_socket_policies[0] = policy_id;
2298 }
2299
2300 if (ip_output_layer_non_id_conditions) {
2301 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->id, policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS, session->session_order, master_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, ultimate_result, ultimate_result_parameter);
2302
2303 if (policy_id == 0) {
2304 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
2305 goto fail;
2306 }
2307
2308 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
2309 }
2310
2311 if (ip_output_layer_id_condition) {
2312 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->id, policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION, session->session_order, 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, ultimate_result, ultimate_result_parameter);
2313
2314 if (policy_id == 0) {
2315 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
2316 goto fail;
2317 }
2318
2319 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
2320 }
2321
2322 // Extra policies for IP Output tunnels for when packets loop back
2323 if (ip_output_layer_tunnel_condition_from_id) {
2324 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->id, policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION, session->session_order, 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, secondary_result, secondary_result_parameter);
2325
2326 if (policy_id == 0) {
2327 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
2328 goto fail;
2329 }
2330
2331 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
2332 }
2333
2334 if (ip_output_layer_tunnel_condition_from_id) {
2335 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(policy->id, policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION, session->session_order, 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, secondary_result, secondary_result_parameter);
2336
2337 if (policy_id == 0) {
2338 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
2339 goto fail;
2340 }
2341
2342 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
2343 }
2344
2345 policy->applied = TRUE;
2346 policy->pending_update = FALSE;
2347 return (TRUE);
2348
2349 fail:
2350 return (FALSE);
2351 }
2352
2353 static void
2354 necp_policy_apply_all(struct necp_session *session)
2355 {
2356 struct necp_session_policy *policy = NULL;
2357 struct necp_session_policy *temp_policy = NULL;
2358
2359 lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2360
2361 // Remove exisiting applied policies
2362 if (session->dirty) {
2363 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
2364 if (policy->pending_deletion) {
2365 if (policy->applied) {
2366 necp_policy_unapply(policy);
2367 }
2368 // Delete the policy
2369 necp_policy_delete(session, policy);
2370 } else if (!policy->applied) {
2371 necp_policy_apply(session, policy);
2372 } else if (policy->pending_update) {
2373 // Must have been applied, but needs an update. Remove and re-add.
2374 necp_policy_unapply(policy);
2375 necp_policy_apply(session, policy);
2376 }
2377 }
2378
2379 necp_kernel_socket_policies_update_uuid_table();
2380 necp_kernel_socket_policies_reprocess();
2381 necp_kernel_ip_output_policies_reprocess();
2382
2383 // Clear dirty bit flags
2384 session->dirty = FALSE;
2385 }
2386
2387 lck_rw_done(&necp_kernel_policy_lock);
2388
2389 if (necp_debug) {
2390 NECPLOG0(LOG_DEBUG, "Applied NECP policies");
2391 }
2392 }
2393
2394 // Kernel Policy Management
2395 // ---------------------
2396 // Kernel policies are derived from session policies
2397 static necp_kernel_policy_id
2398 necp_kernel_policy_get_new_id(void)
2399 {
2400 necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
2401
2402 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2403
2404 necp_last_kernel_policy_id++;
2405 if (necp_last_kernel_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID) {
2406 necp_last_kernel_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID;
2407 }
2408
2409 newid = necp_last_kernel_policy_id;
2410 if (newid == NECP_KERNEL_POLICY_ID_NONE) {
2411 NECPLOG0(LOG_DEBUG, "Allocate kernel policy id failed.\n");
2412 return (0);
2413 }
2414
2415 return (newid);
2416 }
2417
2418 #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)
2419 static necp_kernel_policy_id
2420 necp_kernel_socket_policy_add(necp_policy_id parent_policy_id, necp_policy_order order, u_int32_t session_order, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, u_int32_t cond_account_id, char *cond_domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
2421 {
2422 struct necp_kernel_socket_policy *new_kernel_policy = NULL;
2423 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
2424
2425 MALLOC_ZONE(new_kernel_policy, struct necp_kernel_socket_policy *, sizeof(*new_kernel_policy), M_NECP_SOCKET_POLICY, M_WAITOK);
2426 if (new_kernel_policy == NULL) {
2427 goto done;
2428 }
2429
2430 memset(new_kernel_policy, 0, sizeof(*new_kernel_policy));
2431 new_kernel_policy->parent_policy_id = parent_policy_id;
2432 new_kernel_policy->id = necp_kernel_policy_get_new_id();
2433 new_kernel_policy->order = order;
2434 new_kernel_policy->session_order = session_order;
2435
2436 // Sanitize condition mask
2437 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
2438 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
2439 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
2440 }
2441 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
2442 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
2443 }
2444 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
2445 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_ENTITLEMENT;
2446 }
2447 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
2448 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
2449 }
2450 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
2451 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
2452 }
2453 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
2454
2455 // Set condition values
2456 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
2457 new_kernel_policy->cond_app_id = cond_app_id;
2458 }
2459 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
2460 new_kernel_policy->cond_real_app_id = cond_real_app_id;
2461 }
2462 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
2463 new_kernel_policy->cond_account_id = cond_account_id;
2464 }
2465 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
2466 new_kernel_policy->cond_domain = cond_domain;
2467 new_kernel_policy->cond_domain_dot_count = necp_count_dots(cond_domain, strlen(cond_domain));
2468 }
2469 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
2470 new_kernel_policy->cond_pid = cond_pid;
2471 }
2472 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
2473 new_kernel_policy->cond_uid = cond_uid;
2474 }
2475 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
2476 if (cond_bound_interface) {
2477 ifnet_reference(cond_bound_interface);
2478 }
2479 new_kernel_policy->cond_bound_interface = cond_bound_interface;
2480 }
2481 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
2482 new_kernel_policy->cond_traffic_class = cond_traffic_class;
2483 }
2484 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
2485 new_kernel_policy->cond_protocol = cond_protocol;
2486 }
2487 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
2488 memcpy(&new_kernel_policy->cond_local_start, cond_local_start, cond_local_start->sa.sa_len);
2489 }
2490 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
2491 memcpy(&new_kernel_policy->cond_local_end, cond_local_end, cond_local_end->sa.sa_len);
2492 }
2493 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
2494 new_kernel_policy->cond_local_prefix = cond_local_prefix;
2495 }
2496 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
2497 memcpy(&new_kernel_policy->cond_remote_start, cond_remote_start, cond_remote_start->sa.sa_len);
2498 }
2499 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
2500 memcpy(&new_kernel_policy->cond_remote_end, cond_remote_end, cond_remote_end->sa.sa_len);
2501 }
2502 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
2503 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
2504 }
2505
2506 new_kernel_policy->result = result;
2507 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
2508
2509 if (necp_debug) {
2510 NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%x\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
2511 }
2512 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
2513 done:
2514 return (new_kernel_policy ? new_kernel_policy->id : 0);
2515 }
2516
2517 static struct necp_kernel_socket_policy *
2518 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
2519 {
2520 struct necp_kernel_socket_policy *kernel_policy = NULL;
2521 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
2522
2523 if (policy_id == 0) {
2524 return (NULL);
2525 }
2526
2527 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
2528 if (kernel_policy->id == policy_id) {
2529 return (kernel_policy);
2530 }
2531 }
2532
2533 return (NULL);
2534 }
2535
2536 static bool
2537 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
2538 {
2539 struct necp_kernel_socket_policy *policy = NULL;
2540
2541 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2542
2543 policy = necp_kernel_socket_policy_find(policy_id);
2544 if (policy) {
2545 LIST_REMOVE(policy, chain);
2546
2547 if (policy->cond_bound_interface) {
2548 ifnet_release(policy->cond_bound_interface);
2549 policy->cond_bound_interface = NULL;
2550 }
2551
2552 if (policy->cond_domain) {
2553 FREE(policy->cond_domain, M_NECP);
2554 policy->cond_domain = NULL;
2555 }
2556
2557 FREE_ZONE(policy, sizeof(*policy), M_NECP_SOCKET_POLICY);
2558 return (TRUE);
2559 }
2560
2561 return (FALSE);
2562 }
2563
2564 static void
2565 necp_kernel_socket_policies_dump_all(void)
2566 {
2567 struct necp_kernel_socket_policy *policy = NULL;
2568 int policy_i;
2569 int app_i;
2570
2571 if (necp_debug) {
2572 NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
2573 NECPLOG0(LOG_DEBUG, "-----------\n");
2574 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
2575 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
2576 NECPLOG(LOG_DEBUG, "\t%d. Policy ID: %d, Order: %d.%d, Mask: %x, Result: %d, Parameter: %d\n", policy_i, policy->id, policy->session_order, policy->order, policy->condition_mask, policy->result, policy->result_parameter);
2577 }
2578 if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
2579 NECPLOG0(LOG_DEBUG, "-----------\n");
2580 }
2581
2582 NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
2583 NECPLOG0(LOG_DEBUG, "-----------\n");
2584 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2585 NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
2586 for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
2587 policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
2588 NECPLOG(LOG_DEBUG, "\t%d. Policy ID: %d, Order: %d.%d, Mask: %x, Result: %d, Parameter: %d\n", policy_i, policy->id, policy->session_order, policy->order, policy->condition_mask, policy->result, policy->result_parameter);
2589 }
2590 NECPLOG0(LOG_DEBUG, "-----------\n");
2591 }
2592 }
2593 }
2594
2595 static inline bool
2596 necp_kernel_socket_result_is_service_type(struct necp_kernel_socket_policy *kernel_policy)
2597 {
2598 return (kernel_policy->result >= NECP_KERNEL_POLICY_RESULT_TRIGGER && kernel_policy->result <= NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED);
2599 }
2600
2601 static inline bool
2602 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
2603 {
2604 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
2605 // Drop always cancels out lower policies
2606 return (TRUE);
2607 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
2608 // Filters never cancel out lower policies
2609 return (FALSE);
2610 } else if (necp_kernel_socket_result_is_service_type(upper_policy)) {
2611 // Trigger/Scoping policies can overlap one another, but not other results
2612 return (necp_kernel_socket_result_is_service_type(lower_policy));
2613 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
2614 if (upper_policy->session_order != lower_policy->session_order) {
2615 // A skip cannot override a policy of a different session
2616 return (FALSE);
2617 } else {
2618 if (upper_policy->result_parameter.skip_policy_order == 0 ||
2619 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
2620 // This policy is beyond the skip
2621 return (FALSE);
2622 } else {
2623 // This policy is inside the skip
2624 return (TRUE);
2625 }
2626 }
2627 }
2628
2629 // A hard pass, flow divert, or tunnel will currently block out lower policies
2630 return (TRUE);
2631 }
2632
2633 static bool
2634 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy **policy_array, int valid_indices)
2635 {
2636 bool can_skip = FALSE;
2637 u_int32_t highest_skip_session_order = 0;
2638 u_int32_t highest_skip_order = 0;
2639 int i;
2640 for (i = 0; i < valid_indices; i++) {
2641 struct necp_kernel_socket_policy *compared_policy = policy_array[i];
2642
2643 // For policies in a skip window, we can't mark conflicting policies as unnecessary
2644 if (can_skip) {
2645 if (highest_skip_session_order != compared_policy->session_order ||
2646 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
2647 // If we've moved on to the next session, or passed the skip window
2648 highest_skip_session_order = 0;
2649 highest_skip_order = 0;
2650 can_skip = FALSE;
2651 } else {
2652 // If this policy is also a skip, in can increase the skip window
2653 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
2654 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
2655 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
2656 }
2657 }
2658 continue;
2659 }
2660 }
2661
2662 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
2663 // This policy is a skip. Set the skip window accordingly
2664 can_skip = TRUE;
2665 highest_skip_session_order = compared_policy->session_order;
2666 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
2667 }
2668
2669 // The result of the compared policy must be able to block out this policy result
2670 if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
2671 continue;
2672 }
2673
2674 // If new policy matches All Interfaces, compared policy must also
2675 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
2676 continue;
2677 }
2678
2679 // Default makes lower policies unecessary always
2680 if (compared_policy->condition_mask == 0) {
2681 return (TRUE);
2682 }
2683
2684 // Compared must be more general than policy, and include only conditions within policy
2685 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
2686 continue;
2687 }
2688
2689 // Negative conditions must match for the overlapping conditions
2690 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
2691 continue;
2692 }
2693
2694 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN &&
2695 strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
2696 continue;
2697 }
2698
2699 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
2700 compared_policy->cond_account_id != policy->cond_account_id) {
2701 continue;
2702 }
2703
2704 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
2705 compared_policy->cond_policy_id != policy->cond_policy_id) {
2706 continue;
2707 }
2708
2709 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
2710 compared_policy->cond_app_id != policy->cond_app_id) {
2711 continue;
2712 }
2713
2714 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
2715 compared_policy->cond_real_app_id != policy->cond_real_app_id) {
2716 continue;
2717 }
2718
2719 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
2720 compared_policy->cond_pid != policy->cond_pid) {
2721 continue;
2722 }
2723
2724 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
2725 compared_policy->cond_uid != policy->cond_uid) {
2726 continue;
2727 }
2728
2729 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
2730 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
2731 continue;
2732 }
2733
2734 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
2735 compared_policy->cond_protocol != policy->cond_protocol) {
2736 continue;
2737 }
2738
2739 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
2740 !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
2741 compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
2742 continue;
2743 }
2744
2745 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
2746 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
2747 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)) {
2748 continue;
2749 }
2750 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
2751 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
2752 !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_start, compared_policy->cond_local_prefix)) {
2753 continue;
2754 }
2755 }
2756 }
2757
2758 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
2759 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
2760 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)) {
2761 continue;
2762 }
2763 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
2764 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
2765 !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_start, compared_policy->cond_remote_prefix)) {
2766 continue;
2767 }
2768 }
2769 }
2770
2771 return (TRUE);
2772 }
2773
2774 return (FALSE);
2775 }
2776
2777 static bool
2778 necp_kernel_socket_policies_reprocess(void)
2779 {
2780 int app_i;
2781 int bucket_allocation_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
2782 int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
2783 int app_layer_allocation_count = 0;
2784 int app_layer_current_free_index = 0;
2785 struct necp_kernel_socket_policy *kernel_policy = NULL;
2786
2787 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2788
2789 // Reset mask to 0
2790 necp_kernel_application_policies_condition_mask = 0;
2791 necp_kernel_socket_policies_condition_mask = 0;
2792 necp_kernel_application_policies_count = 0;
2793 necp_kernel_socket_policies_count = 0;
2794 necp_kernel_socket_policies_non_app_count = 0;
2795
2796 // Reset all maps to NULL
2797 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2798 if (necp_kernel_socket_policies_map[app_i] != NULL) {
2799 FREE(necp_kernel_socket_policies_map[app_i], M_NECP);
2800 necp_kernel_socket_policies_map[app_i] = NULL;
2801 }
2802
2803 // Init counts
2804 bucket_allocation_counts[app_i] = 0;
2805 }
2806 if (necp_kernel_socket_policies_app_layer_map != NULL) {
2807 FREE(necp_kernel_socket_policies_app_layer_map, M_NECP);
2808 necp_kernel_socket_policies_app_layer_map = NULL;
2809 }
2810
2811 // Create masks and counts
2812 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
2813 // App layer mask/count
2814 necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
2815 necp_kernel_application_policies_count++;
2816 app_layer_allocation_count++;
2817
2818 // Update socket layer bucket mask/counts
2819 necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
2820 necp_kernel_socket_policies_count++;
2821
2822 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
2823 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
2824 necp_kernel_socket_policies_non_app_count++;
2825 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2826 bucket_allocation_counts[app_i]++;
2827 }
2828 } else {
2829 bucket_allocation_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
2830 }
2831 }
2832
2833 // Allocate maps
2834 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2835 if (bucket_allocation_counts[app_i] > 0) {
2836 // Allocate a NULL-terminated array of policy pointers for each bucket
2837 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);
2838 if (necp_kernel_socket_policies_map[app_i] == NULL) {
2839 goto fail;
2840 }
2841
2842 // Initialize the first entry to NULL
2843 (necp_kernel_socket_policies_map[app_i])[0] = NULL;
2844 }
2845 bucket_current_free_index[app_i] = 0;
2846 }
2847 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);
2848 if (necp_kernel_socket_policies_app_layer_map == NULL) {
2849 goto fail;
2850 }
2851 necp_kernel_socket_policies_app_layer_map[0] = NULL;
2852
2853 // Fill out maps
2854 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
2855 // Insert pointers into map
2856 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
2857 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
2858 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2859 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_map[app_i], bucket_current_free_index[app_i])) {
2860 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
2861 bucket_current_free_index[app_i]++;
2862 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
2863 }
2864 }
2865 } else {
2866 app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
2867 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_map[app_i], bucket_current_free_index[app_i])) {
2868 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
2869 bucket_current_free_index[app_i]++;
2870 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
2871 }
2872 }
2873
2874 if (!necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
2875 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
2876 app_layer_current_free_index++;
2877 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
2878 }
2879 }
2880 necp_kernel_socket_policies_dump_all();
2881 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
2882 return (TRUE);
2883
2884 fail:
2885 // Free memory, reset masks to 0
2886 necp_kernel_application_policies_condition_mask = 0;
2887 necp_kernel_socket_policies_condition_mask = 0;
2888 necp_kernel_application_policies_count = 0;
2889 necp_kernel_socket_policies_count = 0;
2890 necp_kernel_socket_policies_non_app_count = 0;
2891 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
2892 if (necp_kernel_socket_policies_map[app_i] != NULL) {
2893 FREE(necp_kernel_socket_policies_map[app_i], M_NECP);
2894 necp_kernel_socket_policies_map[app_i] = NULL;
2895 }
2896 }
2897 if (necp_kernel_socket_policies_app_layer_map != NULL) {
2898 FREE(necp_kernel_socket_policies_app_layer_map, M_NECP);
2899 necp_kernel_socket_policies_app_layer_map = NULL;
2900 }
2901 return (FALSE);
2902 }
2903
2904 static u_int32_t
2905 necp_get_new_string_id(void)
2906 {
2907 u_int32_t newid = 0;
2908
2909 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2910
2911 necp_last_string_id++;
2912 if (necp_last_string_id < 1) {
2913 necp_last_string_id = 1;
2914 }
2915
2916 newid = necp_last_string_id;
2917 if (newid == 0) {
2918 NECPLOG0(LOG_DEBUG, "Allocate string id failed.\n");
2919 return (0);
2920 }
2921
2922 return (newid);
2923 }
2924
2925 static struct necp_string_id_mapping *
2926 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string)
2927 {
2928 struct necp_string_id_mapping *searchentry = NULL;
2929 struct necp_string_id_mapping *foundentry = NULL;
2930
2931 LIST_FOREACH(searchentry, list, chain) {
2932 if (strcmp(searchentry->string, string) == 0) {
2933 foundentry = searchentry;
2934 break;
2935 }
2936 }
2937
2938 return (foundentry);
2939 }
2940
2941 static u_int32_t
2942 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
2943 {
2944 u_int32_t string_id = 0;
2945 struct necp_string_id_mapping *existing_mapping = NULL;
2946
2947 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2948
2949 existing_mapping = necp_lookup_string_to_id_locked(list, string);
2950 if (existing_mapping != NULL) {
2951 string_id = existing_mapping->id;
2952 existing_mapping->refcount++;
2953 } else {
2954 struct necp_string_id_mapping *new_mapping = NULL;
2955 MALLOC(new_mapping, struct necp_string_id_mapping *, sizeof(struct necp_string_id_mapping), M_NECP, M_WAITOK);
2956 if (new_mapping != NULL) {
2957 memset(new_mapping, 0, sizeof(struct necp_string_id_mapping));
2958
2959 size_t length = strlen(string) + 1;
2960 MALLOC(new_mapping->string, char *, length, M_NECP, M_WAITOK);
2961 if (new_mapping->string != NULL) {
2962 memcpy(new_mapping->string, string, length);
2963 new_mapping->id = necp_get_new_string_id();
2964 new_mapping->refcount = 1;
2965 LIST_INSERT_HEAD(list, new_mapping, chain);
2966 string_id = new_mapping->id;
2967 } else {
2968 FREE(new_mapping, M_NECP);
2969 new_mapping = NULL;
2970 }
2971 }
2972 }
2973 return (string_id);
2974 }
2975
2976 static bool
2977 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
2978 {
2979 struct necp_string_id_mapping *existing_mapping = NULL;
2980
2981 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
2982
2983 existing_mapping = necp_lookup_string_to_id_locked(list, string);
2984 if (existing_mapping != NULL) {
2985 if (--existing_mapping->refcount == 0) {
2986 LIST_REMOVE(existing_mapping, chain);
2987 FREE(existing_mapping->string, M_NECP);
2988 FREE(existing_mapping, M_NECP);
2989 }
2990 return (TRUE);
2991 }
2992
2993 return (FALSE);
2994 }
2995
2996 #define NECP_NULL_SERVICE_ID 1
2997 static u_int32_t
2998 necp_get_new_uuid_id(void)
2999 {
3000 u_int32_t newid = 0;
3001
3002 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3003
3004 necp_last_uuid_id++;
3005 if (necp_last_uuid_id < (NECP_NULL_SERVICE_ID + 1)) {
3006 necp_last_uuid_id = (NECP_NULL_SERVICE_ID + 1);
3007 }
3008
3009 newid = necp_last_uuid_id;
3010 if (newid == 0) {
3011 NECPLOG0(LOG_DEBUG, "Allocate uuid id failed.\n");
3012 return (0);
3013 }
3014
3015 return (newid);
3016 }
3017
3018 static struct necp_uuid_id_mapping *
3019 necp_uuid_lookup_app_id_locked(uuid_t uuid)
3020 {
3021 struct necp_uuid_id_mapping *searchentry = NULL;
3022 struct necp_uuid_id_mapping *foundentry = NULL;
3023
3024 LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
3025 if (uuid_compare(searchentry->uuid, uuid) == 0) {
3026 foundentry = searchentry;
3027 break;
3028 }
3029 }
3030
3031 return (foundentry);
3032 }
3033
3034 static u_int32_t
3035 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
3036 {
3037 u_int32_t local_id = 0;
3038 struct necp_uuid_id_mapping *existing_mapping = NULL;
3039
3040 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3041
3042 if (allocated_mapping) {
3043 *allocated_mapping = FALSE;
3044 }
3045
3046 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
3047 if (existing_mapping != NULL) {
3048 local_id = existing_mapping->id;
3049 existing_mapping->refcount++;
3050 if (uuid_policy_table) {
3051 existing_mapping->table_refcount++;
3052 }
3053 } else {
3054 struct necp_uuid_id_mapping *new_mapping = NULL;
3055 MALLOC(new_mapping, struct necp_uuid_id_mapping *, sizeof(*new_mapping), M_NECP, M_WAITOK);
3056 if (new_mapping != NULL) {
3057 uuid_copy(new_mapping->uuid, uuid);
3058 new_mapping->id = necp_get_new_uuid_id();
3059 new_mapping->refcount = 1;
3060 if (uuid_policy_table) {
3061 new_mapping->table_refcount = 1;
3062 } else {
3063 new_mapping->table_refcount = 0;
3064 }
3065
3066 LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
3067
3068 if (allocated_mapping) {
3069 *allocated_mapping = TRUE;
3070 }
3071
3072 local_id = new_mapping->id;
3073 }
3074 }
3075
3076 return (local_id);
3077 }
3078
3079 static bool
3080 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
3081 {
3082 struct necp_uuid_id_mapping *existing_mapping = NULL;
3083
3084 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3085
3086 if (removed_mapping) {
3087 *removed_mapping = FALSE;
3088 }
3089
3090 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
3091 if (existing_mapping != NULL) {
3092 if (uuid_policy_table) {
3093 existing_mapping->table_refcount--;
3094 }
3095 if (--existing_mapping->refcount == 0) {
3096 LIST_REMOVE(existing_mapping, chain);
3097 FREE(existing_mapping, M_NECP);
3098 if (removed_mapping) {
3099 *removed_mapping = TRUE;
3100 }
3101 }
3102 return (TRUE);
3103 }
3104
3105 return (FALSE);
3106 }
3107
3108 static struct necp_uuid_id_mapping *
3109 necp_uuid_get_null_service_id_mapping(void)
3110 {
3111 static struct necp_uuid_id_mapping null_mapping;
3112 uuid_clear(null_mapping.uuid);
3113 null_mapping.id = NECP_NULL_SERVICE_ID;
3114
3115 return (&null_mapping);
3116 }
3117
3118 static struct necp_uuid_id_mapping *
3119 necp_uuid_lookup_service_id_locked(uuid_t uuid)
3120 {
3121 struct necp_uuid_id_mapping *searchentry = NULL;
3122 struct necp_uuid_id_mapping *foundentry = NULL;
3123
3124 if (uuid_is_null(uuid)) {
3125 return necp_uuid_get_null_service_id_mapping();
3126 }
3127
3128 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
3129 if (uuid_compare(searchentry->uuid, uuid) == 0) {
3130 foundentry = searchentry;
3131 break;
3132 }
3133 }
3134
3135 return (foundentry);
3136 }
3137
3138 static struct necp_uuid_id_mapping *
3139 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
3140 {
3141 struct necp_uuid_id_mapping *searchentry = NULL;
3142 struct necp_uuid_id_mapping *foundentry = NULL;
3143
3144 if (local_id == NECP_NULL_SERVICE_ID) {
3145 return necp_uuid_get_null_service_id_mapping();
3146 }
3147
3148 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
3149 if (searchentry->id == local_id) {
3150 foundentry = searchentry;
3151 break;
3152 }
3153 }
3154
3155 return (foundentry);
3156 }
3157
3158 static u_int32_t
3159 necp_create_uuid_service_id_mapping(uuid_t uuid)
3160 {
3161 u_int32_t local_id = 0;
3162 struct necp_uuid_id_mapping *existing_mapping = NULL;
3163
3164 if (uuid_is_null(uuid)) {
3165 return (NECP_NULL_SERVICE_ID);
3166 }
3167
3168 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3169
3170 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
3171 if (existing_mapping != NULL) {
3172 local_id = existing_mapping->id;
3173 existing_mapping->refcount++;
3174 } else {
3175 struct necp_uuid_id_mapping *new_mapping = NULL;
3176 MALLOC(new_mapping, struct necp_uuid_id_mapping *, sizeof(*new_mapping), M_NECP, M_WAITOK);
3177 if (new_mapping != NULL) {
3178 uuid_copy(new_mapping->uuid, uuid);
3179 new_mapping->id = necp_get_new_uuid_id();
3180 new_mapping->refcount = 1;
3181
3182 LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
3183
3184 local_id = new_mapping->id;
3185 }
3186 }
3187
3188 return (local_id);
3189 }
3190
3191 static bool
3192 necp_remove_uuid_service_id_mapping(uuid_t uuid)
3193 {
3194 struct necp_uuid_id_mapping *existing_mapping = NULL;
3195
3196 if (uuid_is_null(uuid)) {
3197 return (TRUE);
3198 }
3199
3200 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3201
3202 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
3203 if (existing_mapping != NULL) {
3204 if (--existing_mapping->refcount == 0) {
3205 LIST_REMOVE(existing_mapping, chain);
3206 FREE(existing_mapping, M_NECP);
3207 }
3208 return (TRUE);
3209 }
3210
3211 return (FALSE);
3212 }
3213
3214
3215 static bool
3216 necp_kernel_socket_policies_update_uuid_table(void)
3217 {
3218 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3219
3220 if (necp_uuid_app_id_mappings_dirty) {
3221 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, NULL, PROC_UUID_NECP_APP_POLICY) < 0) {
3222 NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
3223 return (FALSE);
3224 }
3225
3226 if (necp_num_uuid_app_id_mappings > 0) {
3227 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
3228 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--) {
3229 struct necp_uuid_id_mapping *mapping = NULL;
3230 LIST_FOREACH(mapping, uuid_list_head, chain) {
3231 if (mapping->table_refcount > 0 &&
3232 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
3233 NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
3234 }
3235 }
3236 }
3237 }
3238
3239 necp_uuid_app_id_mappings_dirty = FALSE;
3240 }
3241
3242 return (TRUE);
3243 }
3244
3245 #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)
3246 static necp_kernel_policy_id
3247 necp_kernel_ip_output_policy_add(necp_policy_id parent_policy_id, necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, 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, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
3248 {
3249 struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
3250 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
3251
3252 MALLOC_ZONE(new_kernel_policy, struct necp_kernel_ip_output_policy *, sizeof(*new_kernel_policy), M_NECP_IP_POLICY, M_WAITOK);
3253 if (new_kernel_policy == NULL) {
3254 goto done;
3255 }
3256
3257 memset(new_kernel_policy, 0, sizeof(*new_kernel_policy));
3258 new_kernel_policy->parent_policy_id = parent_policy_id;
3259 new_kernel_policy->id = necp_kernel_policy_get_new_id();
3260 new_kernel_policy->suborder = suborder;
3261 new_kernel_policy->order = order;
3262 new_kernel_policy->session_order = session_order;
3263
3264 // Sanitize condition mask
3265 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
3266 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
3267 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
3268 }
3269 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
3270 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
3271 }
3272 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
3273 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
3274 }
3275 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
3276
3277 // Set condition values
3278 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
3279 new_kernel_policy->cond_policy_id = cond_policy_id;
3280 }
3281 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3282 if (cond_bound_interface) {
3283 ifnet_reference(cond_bound_interface);
3284 }
3285 new_kernel_policy->cond_bound_interface = cond_bound_interface;
3286 }
3287 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
3288 new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
3289 }
3290 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3291 new_kernel_policy->cond_protocol = cond_protocol;
3292 }
3293 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3294 memcpy(&new_kernel_policy->cond_local_start, cond_local_start, cond_local_start->sa.sa_len);
3295 }
3296 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3297 memcpy(&new_kernel_policy->cond_local_end, cond_local_end, cond_local_end->sa.sa_len);
3298 }
3299 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
3300 new_kernel_policy->cond_local_prefix = cond_local_prefix;
3301 }
3302 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3303 memcpy(&new_kernel_policy->cond_remote_start, cond_remote_start, cond_remote_start->sa.sa_len);
3304 }
3305 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3306 memcpy(&new_kernel_policy->cond_remote_end, cond_remote_end, cond_remote_end->sa.sa_len);
3307 }
3308 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
3309 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
3310 }
3311
3312 new_kernel_policy->result = result;
3313 memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
3314
3315 if (necp_debug) {
3316 NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%x\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
3317 }
3318 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
3319 done:
3320 return (new_kernel_policy ? new_kernel_policy->id : 0);
3321 }
3322
3323 static struct necp_kernel_ip_output_policy *
3324 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
3325 {
3326 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
3327 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
3328
3329 if (policy_id == 0) {
3330 return (NULL);
3331 }
3332
3333 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
3334 if (kernel_policy->id == policy_id) {
3335 return (kernel_policy);
3336 }
3337 }
3338
3339 return (NULL);
3340 }
3341
3342 static bool
3343 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
3344 {
3345 struct necp_kernel_ip_output_policy *policy = NULL;
3346
3347 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3348
3349 policy = necp_kernel_ip_output_policy_find(policy_id);
3350 if (policy) {
3351 LIST_REMOVE(policy, chain);
3352
3353 if (policy->cond_bound_interface) {
3354 ifnet_release(policy->cond_bound_interface);
3355 policy->cond_bound_interface = NULL;
3356 }
3357
3358 FREE_ZONE(policy, sizeof(*policy), M_NECP_IP_POLICY);
3359 return (TRUE);
3360 }
3361
3362 return (FALSE);
3363 }
3364
3365 static void
3366 necp_kernel_ip_output_policies_dump_all(void)
3367 {
3368 struct necp_kernel_ip_output_policy *policy = NULL;
3369 int policy_i;
3370 int id_i;
3371
3372 if (necp_debug) {
3373 NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
3374 NECPLOG0(LOG_DEBUG, "-----------\n");
3375 for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
3376 NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
3377 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++) {
3378 policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
3379 NECPLOG(LOG_DEBUG, "\t%d. Policy ID: %d, Order: %d.%d.%d, Mask: %x, Result: %d, Parameter: %d\n", policy_i, policy->id, policy->session_order, policy->order, policy->suborder, policy->condition_mask, policy->result, policy->result_parameter);
3380 }
3381 NECPLOG0(LOG_DEBUG, "-----------\n");
3382 }
3383 }
3384 }
3385
3386 static inline bool
3387 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
3388 {
3389 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
3390 if (upper_policy->session_order != lower_policy->session_order) {
3391 // A skip cannot override a policy of a different session
3392 return (FALSE);
3393 } else {
3394 if (upper_policy->result_parameter.skip_policy_order == 0 ||
3395 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
3396 // This policy is beyond the skip
3397 return (FALSE);
3398 } else {
3399 // This policy is inside the skip
3400 return (TRUE);
3401 }
3402 }
3403 }
3404
3405 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
3406 return (TRUE);
3407 }
3408
3409 static bool
3410 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)
3411 {
3412 bool can_skip = FALSE;
3413 u_int32_t highest_skip_session_order = 0;
3414 u_int32_t highest_skip_order = 0;
3415 int i;
3416 for (i = 0; i < valid_indices; i++) {
3417 struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
3418
3419 // For policies in a skip window, we can't mark conflicting policies as unnecessary
3420 if (can_skip) {
3421 if (highest_skip_session_order != compared_policy->session_order ||
3422 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
3423 // If we've moved on to the next session, or passed the skip window
3424 highest_skip_session_order = 0;
3425 highest_skip_order = 0;
3426 can_skip = FALSE;
3427 } else {
3428 // If this policy is also a skip, in can increase the skip window
3429 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
3430 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
3431 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
3432 }
3433 }
3434 continue;
3435 }
3436 }
3437
3438 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
3439 // This policy is a skip. Set the skip window accordingly
3440 can_skip = TRUE;
3441 highest_skip_session_order = compared_policy->session_order;
3442 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
3443 }
3444
3445 // The result of the compared policy must be able to block out this policy result
3446 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
3447 continue;
3448 }
3449
3450 // If new policy matches All Interfaces, compared policy must also
3451 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
3452 continue;
3453 }
3454
3455 // Default makes lower policies unecessary always
3456 if (compared_policy->condition_mask == 0) {
3457 return (TRUE);
3458 }
3459
3460 // Compared must be more general than policy, and include only conditions within policy
3461 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
3462 continue;
3463 }
3464
3465 // Negative conditions must match for the overlapping conditions
3466 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
3467 continue;
3468 }
3469
3470 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
3471 compared_policy->cond_policy_id != policy->cond_policy_id) {
3472 continue;
3473 }
3474
3475 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
3476 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
3477 continue;
3478 }
3479
3480 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
3481 compared_policy->cond_protocol != policy->cond_protocol) {
3482 continue;
3483 }
3484
3485 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3486 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3487 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)) {
3488 continue;
3489 }
3490 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
3491 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
3492 !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_start, compared_policy->cond_local_prefix)) {
3493 continue;
3494 }
3495 }
3496 }
3497
3498 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3499 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3500 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)) {
3501 continue;
3502 }
3503 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
3504 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
3505 !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_start, compared_policy->cond_remote_prefix)) {
3506 continue;
3507 }
3508 }
3509 }
3510
3511 return (TRUE);
3512 }
3513
3514 return (FALSE);
3515 }
3516
3517 static bool
3518 necp_kernel_ip_output_policies_reprocess(void)
3519 {
3520 int i;
3521 int bucket_allocation_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
3522 int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
3523 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
3524
3525 lck_rw_assert(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3526
3527 // Reset mask to 0
3528 necp_kernel_ip_output_policies_condition_mask = 0;
3529 necp_kernel_ip_output_policies_count = 0;
3530 necp_kernel_ip_output_policies_non_id_count = 0;
3531
3532 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3533 if (necp_kernel_ip_output_policies_map[i] != NULL) {
3534 FREE(necp_kernel_ip_output_policies_map[i], M_NECP);
3535 necp_kernel_ip_output_policies_map[i] = NULL;
3536 }
3537
3538 // Init counts
3539 bucket_allocation_counts[i] = 0;
3540 }
3541
3542 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
3543 // Update mask
3544 necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
3545 necp_kernel_ip_output_policies_count++;
3546
3547 // Update bucket counts
3548 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
3549 necp_kernel_ip_output_policies_non_id_count++;
3550 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3551 bucket_allocation_counts[i]++;
3552 }
3553 } else {
3554 bucket_allocation_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
3555 }
3556 }
3557
3558 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3559 if (bucket_allocation_counts[i] > 0) {
3560 // Allocate a NULL-terminated array of policy pointers for each bucket
3561 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);
3562 if (necp_kernel_ip_output_policies_map[i] == NULL) {
3563 goto fail;
3564 }
3565
3566 // Initialize the first entry to NULL
3567 (necp_kernel_ip_output_policies_map[i])[0] = NULL;
3568 }
3569 bucket_current_free_index[i] = 0;
3570 }
3571
3572 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
3573 // Insert pointers into map
3574 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
3575 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3576 if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy, necp_kernel_ip_output_policies_map[i], bucket_current_free_index[i])) {
3577 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
3578 bucket_current_free_index[i]++;
3579 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
3580 }
3581 }
3582 } else {
3583 i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
3584 if (!necp_kernel_ip_output_policy_is_unnecessary(kernel_policy, necp_kernel_ip_output_policies_map[i], bucket_current_free_index[i])) {
3585 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
3586 bucket_current_free_index[i]++;
3587 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
3588 }
3589 }
3590 }
3591 necp_kernel_ip_output_policies_dump_all();
3592 return (TRUE);
3593
3594 fail:
3595 // Free memory, reset mask to 0
3596 necp_kernel_ip_output_policies_condition_mask = 0;
3597 necp_kernel_ip_output_policies_count = 0;
3598 necp_kernel_ip_output_policies_non_id_count = 0;
3599 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
3600 if (necp_kernel_ip_output_policies_map[i] != NULL) {
3601 FREE(necp_kernel_ip_output_policies_map[i], M_NECP);
3602 necp_kernel_ip_output_policies_map[i] = NULL;
3603 }
3604 }
3605 return (FALSE);
3606 }
3607
3608 // Outbound Policy Matching
3609 // ---------------------
3610 struct substring {
3611 char *string;
3612 size_t length;
3613 };
3614
3615 static struct substring
3616 necp_trim_dots_and_stars(char *string, size_t length)
3617 {
3618 struct substring sub;
3619 sub.string = string;
3620 sub.length = string ? length : 0;
3621
3622 while (sub.length && (sub.string[0] == '.' || sub.string[0] == '*')) {
3623 sub.string++;
3624 sub.length--;
3625 }
3626
3627 while (sub.length && (sub.string[sub.length - 1] == '.' || sub.string[sub.length - 1] == '*')) {
3628 sub.length--;
3629 }
3630
3631 return (sub);
3632 }
3633
3634 static char *
3635 necp_create_trimmed_domain(char *string, size_t length)
3636 {
3637 char *trimmed_domain = NULL;
3638 struct substring sub = necp_trim_dots_and_stars(string, length);
3639
3640 MALLOC(trimmed_domain, char *, sub.length + 1, M_NECP, M_WAITOK);
3641 if (trimmed_domain == NULL) {
3642 return (NULL);
3643 }
3644
3645 memcpy(trimmed_domain, sub.string, sub.length);
3646 trimmed_domain[sub.length] = 0;
3647
3648 return (trimmed_domain);
3649 }
3650
3651 static inline int
3652 necp_count_dots(char *string, size_t length)
3653 {
3654 int dot_count = 0;
3655 size_t i = 0;
3656
3657 for (i = 0; i < length; i++) {
3658 if (string[i] == '.') {
3659 dot_count++;
3660 }
3661 }
3662
3663 return (dot_count);
3664 }
3665
3666 static bool
3667 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
3668 {
3669 if (parent.length <= suffix.length) {
3670 return (FALSE);
3671 }
3672
3673 size_t length_difference = (parent.length - suffix.length);
3674
3675 if (require_dot_before_suffix) {
3676 if (((char *)(parent.string + length_difference - 1))[0] != '.') {
3677 return (FALSE);
3678 }
3679 }
3680
3681 return (memcmp(parent.string + length_difference, suffix.string, suffix.length) == 0);
3682 }
3683
3684 static bool
3685 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain, u_int8_t domain_dot_count)
3686 {
3687 if (hostname_substring.string == NULL || domain == NULL) {
3688 return (hostname_substring.string == domain);
3689 }
3690
3691 struct substring domain_substring;
3692 domain_substring.string = domain;
3693 domain_substring.length = strlen(domain);
3694
3695 if (hostname_dot_count == domain_dot_count) {
3696 if (hostname_substring.length == domain_substring.length &&
3697 memcmp(hostname_substring.string, domain_substring.string, hostname_substring.length) == 0) {
3698 return (TRUE);
3699 }
3700 } else if (domain_dot_count > 0 && domain_dot_count < hostname_dot_count) {
3701 if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
3702 return (TRUE);
3703 }
3704 }
3705
3706 return (FALSE);
3707 }
3708
3709 static void
3710 necp_application_fillout_info_locked(uuid_t application_uuid, uuid_t real_application_uuid, char *account, char *domain, pid_t pid, uid_t uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, struct necp_socket_info *info)
3711 {
3712 memset(info, 0, sizeof(struct necp_socket_info));
3713
3714 info->pid = pid;
3715 info->uid = uid;
3716 info->protocol = protocol;
3717 info->bound_interface_index = bound_interface_index;
3718 info->traffic_class = traffic_class;
3719 info->cred_result = 0; // Don't check the entitlement here, only in the socket layer
3720
3721 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
3722 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
3723 if (existing_mapping) {
3724 info->application_id = existing_mapping->id;
3725 }
3726 }
3727
3728 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
3729 if (uuid_compare(application_uuid, real_application_uuid) == 0) {
3730 info->real_application_id = info->application_id;
3731 } else {
3732 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
3733 if (existing_mapping) {
3734 info->real_application_id = existing_mapping->id;
3735 }
3736 }
3737 }
3738
3739 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
3740 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
3741 if (existing_mapping) {
3742 info->account_id = existing_mapping->id;
3743 }
3744 }
3745
3746 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
3747 info->domain = domain;
3748 }
3749 }
3750
3751 static int
3752 necp_application_find_policy_match_internal(u_int8_t *parameters, size_t parameters_size, struct necp_aggregate_result *returned_result)
3753 {
3754 int error = 0;
3755 size_t offset = 0;
3756
3757 struct necp_kernel_socket_policy *matched_policy = NULL;
3758 struct necp_socket_info info;
3759 necp_kernel_policy_filter filter_control_unit = 0;
3760 necp_kernel_policy_result service_action = 0;
3761 necp_kernel_policy_service service = { 0, 0 };
3762
3763 pid_t pid = 0;
3764 uid_t uid = 0;
3765 u_int16_t protocol = 0;
3766 u_int32_t bound_interface_index = 0;
3767 u_int32_t traffic_class = 0;
3768
3769 uuid_t application_uuid;
3770 uuid_clear(application_uuid);
3771 uuid_t real_application_uuid;
3772 uuid_clear(real_application_uuid);
3773 char *domain = NULL;
3774 char *account = NULL;
3775
3776 if (returned_result == NULL) {
3777 return (EINVAL);
3778 }
3779
3780 memset(returned_result, 0, sizeof(struct necp_aggregate_result));
3781
3782 lck_rw_lock_shared(&necp_kernel_policy_lock);
3783 if (necp_kernel_application_policies_count == 0) {
3784 if (necp_drop_all_order > 0) {
3785 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
3786 lck_rw_done(&necp_kernel_policy_lock);
3787 return (0);
3788 }
3789 }
3790 lck_rw_done(&necp_kernel_policy_lock);
3791
3792 while (offset < parameters_size) {
3793 u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
3794 size_t length = necp_buffer_get_tlv_length(parameters, offset);
3795
3796 if (length > 0 && (offset + sizeof(u_int8_t) + sizeof(size_t) + length) <= parameters_size) {
3797 u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
3798 if (value != NULL) {
3799 switch (type) {
3800 case NECP_POLICY_CONDITION_APPLICATION: {
3801 if (length >= sizeof(uuid_t)) {
3802 uuid_copy(application_uuid, value);
3803 }
3804 break;
3805 }
3806 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
3807 if (length >= sizeof(uuid_t)) {
3808 uuid_copy(real_application_uuid, value);
3809 }
3810 break;
3811 }
3812 case NECP_POLICY_CONDITION_DOMAIN: {
3813 domain = (char *)value;
3814 domain[length - 1] = 0;
3815 break;
3816 }
3817 case NECP_POLICY_CONDITION_ACCOUNT: {
3818 account = (char *)value;
3819 account[length - 1] = 0;
3820 break;
3821 }
3822 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
3823 if (length >= sizeof(u_int32_t)) {
3824 memcpy(&traffic_class, value, sizeof(u_int32_t));
3825 }
3826 break;
3827 }
3828 case NECP_POLICY_CONDITION_PID: {
3829 if (length >= sizeof(pid_t)) {
3830 memcpy(&pid, value, sizeof(pid_t));
3831 }
3832 break;
3833 }
3834 case NECP_POLICY_CONDITION_UID: {
3835 if (length >= sizeof(uid_t)) {
3836 memcpy(&uid, value, sizeof(uid_t));
3837 }
3838 break;
3839 }
3840 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
3841 if (length >= sizeof(u_int16_t)) {
3842 memcpy(&protocol, value, sizeof(u_int16_t));
3843 }
3844 break;
3845 }
3846 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
3847 if (length <= IFXNAMSIZ && length > 0) {
3848 ifnet_t bound_interface = NULL;
3849 char interface_name[IFXNAMSIZ];
3850 memcpy(interface_name, value, length);
3851 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
3852 if (ifnet_find_by_name(interface_name, &bound_interface) == 0) {
3853 bound_interface_index = bound_interface->if_index;
3854 }
3855 }
3856 break;
3857 }
3858 default: {
3859 break;
3860 }
3861 }
3862 }
3863 }
3864
3865 offset += sizeof(u_int8_t) + sizeof(size_t) + length;
3866 }
3867
3868 // Lock
3869 lck_rw_lock_shared(&necp_kernel_policy_lock);
3870
3871 necp_application_fillout_info_locked(application_uuid, real_application_uuid, account, domain, pid, uid, protocol, bound_interface_index, traffic_class, &info);
3872 matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map, &info, &filter_control_unit, &service_action, &service);
3873 if (matched_policy) {
3874 returned_result->routing_result = matched_policy->result;
3875 memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
3876 } else {
3877 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
3878 }
3879 returned_result->filter_control_unit = filter_control_unit;
3880 returned_result->service_action = service_action;
3881
3882 if (service.identifier != 0) {
3883 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
3884 if (mapping != NULL) {
3885 struct necp_service_registration *service_registration = NULL;
3886 uuid_copy(returned_result->service_uuid, mapping->uuid);
3887 returned_result->service_data = service.data;
3888 if (service.identifier == NECP_NULL_SERVICE_ID) {
3889 // NULL service is always 'registered'
3890 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
3891 } else {
3892 LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
3893 if (service.identifier == service_registration->service_id) {
3894 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
3895 break;
3896 }
3897 }
3898 }
3899 }
3900 }
3901
3902 // Unlock
3903 lck_rw_done(&necp_kernel_policy_lock);
3904
3905 return (error);
3906 }
3907
3908 #define NECP_MAX_MATCH_POLICY_PARAMETER_SIZE 1024
3909
3910 int
3911 necp_match_policy(struct proc *p, struct necp_match_policy_args *uap, int32_t *retval)
3912 {
3913 #pragma unused(p, retval)
3914 u_int8_t *parameters = NULL;
3915 struct necp_aggregate_result returned_result;
3916 int error = 0;
3917
3918 if (uap == NULL) {
3919 error = EINVAL;
3920 goto done;
3921 }
3922
3923 if (uap->parameters == 0 || uap->parameters_size == 0 || uap->parameters_size > NECP_MAX_MATCH_POLICY_PARAMETER_SIZE || uap->returned_result == 0) {
3924 error = EINVAL;
3925 goto done;
3926 }
3927
3928 MALLOC(parameters, u_int8_t *, uap->parameters_size, M_NECP, M_WAITOK);
3929 if (parameters == NULL) {
3930 error = ENOMEM;
3931 goto done;
3932 }
3933 // Copy parameters in
3934 copyin(uap->parameters, parameters, uap->parameters_size);
3935
3936 error = necp_application_find_policy_match_internal(parameters, uap->parameters_size, &returned_result);
3937 if (error) {
3938 goto done;
3939 }
3940
3941 // Copy return value back
3942 copyout(&returned_result, uap->returned_result, sizeof(struct necp_aggregate_result));
3943 done:
3944 if (parameters != NULL) {
3945 FREE(parameters, M_NECP);
3946 }
3947 return (error);
3948 }
3949
3950 static bool
3951 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy, necp_app_id app_id, necp_app_id real_app_id, errno_t cred_result, u_int32_t account_id, struct substring domain, u_int8_t domain_dot_count, pid_t pid, uid_t uid, u_int32_t bound_interface_index, u_int32_t traffic_class, u_int16_t protocol, union necp_sockaddr_union *local, union necp_sockaddr_union *remote)
3952 {
3953 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
3954 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3955 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
3956 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3957 if (bound_interface_index == cond_bound_interface_index) {
3958 // No match, matches forbidden interface
3959 return (FALSE);
3960 }
3961 } else {
3962 if (bound_interface_index != cond_bound_interface_index) {
3963 // No match, does not match required interface
3964 return (FALSE);
3965 }
3966 }
3967 } else {
3968 if (bound_interface_index != 0) {
3969 // No match, requires a non-bound packet
3970 return (FALSE);
3971 }
3972 }
3973 }
3974
3975 if (kernel_policy->condition_mask == 0) {
3976 return (TRUE);
3977 }
3978
3979 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3980 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
3981 if (app_id == kernel_policy->cond_app_id) {
3982 // No match, matches forbidden application
3983 return (FALSE);
3984 }
3985 } else {
3986 if (app_id != kernel_policy->cond_app_id) {
3987 // No match, does not match required application
3988 return (FALSE);
3989 }
3990 }
3991 }
3992
3993 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3994 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3995 if (real_app_id == kernel_policy->cond_real_app_id) {
3996 // No match, matches forbidden application
3997 return (FALSE);
3998 }
3999 } else {
4000 if (real_app_id != kernel_policy->cond_real_app_id) {
4001 // No match, does not match required application
4002 return (FALSE);
4003 }
4004 }
4005 }
4006
4007 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
4008 if (cred_result != 0) {
4009 // Process is missing entitlement
4010 return (FALSE);
4011 }
4012 }
4013
4014 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
4015 bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
4016 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
4017 if (domain_matches) {
4018 // No match, matches forbidden domain
4019 return (FALSE);
4020 }
4021 } else {
4022 if (!domain_matches) {
4023 // No match, does not match required domain
4024 return (FALSE);
4025 }
4026 }
4027 }
4028
4029 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4030 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4031 if (account_id == kernel_policy->cond_account_id) {
4032 // No match, matches forbidden account
4033 return (FALSE);
4034 }
4035 } else {
4036 if (account_id != kernel_policy->cond_account_id) {
4037 // No match, does not match required account
4038 return (FALSE);
4039 }
4040 }
4041 }
4042
4043 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
4044 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
4045 if (pid == kernel_policy->cond_pid) {
4046 // No match, matches forbidden pid
4047 return (FALSE);
4048 }
4049 } else {
4050 if (pid != kernel_policy->cond_pid) {
4051 // No match, does not match required pid
4052 return (FALSE);
4053 }
4054 }
4055 }
4056
4057 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
4058 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
4059 if (uid == kernel_policy->cond_uid) {
4060 // No match, matches forbidden uid
4061 return (FALSE);
4062 }
4063 } else {
4064 if (uid != kernel_policy->cond_uid) {
4065 // No match, does not match required uid
4066 return (FALSE);
4067 }
4068 }
4069 }
4070
4071 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4072 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4073 if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
4074 traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
4075 // No match, matches forbidden traffic class
4076 return (FALSE);
4077 }
4078 } else {
4079 if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
4080 traffic_class > kernel_policy->cond_traffic_class.end_tc) {
4081 // No match, does not match required traffic class
4082 return (FALSE);
4083 }
4084 }
4085 }
4086
4087 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4088 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4089 if (protocol == kernel_policy->cond_protocol) {
4090 // No match, matches forbidden protocol
4091 return (FALSE);
4092 }
4093 } else {
4094 if (protocol != kernel_policy->cond_protocol) {
4095 // No match, does not match required protocol
4096 return (FALSE);
4097 }
4098 }
4099 }
4100
4101 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4102 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4103 bool inRange = necp_is_addr_in_range((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, (struct sockaddr *)&kernel_policy->cond_local_end);
4104 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4105 if (inRange) {
4106 return (FALSE);
4107 }
4108 } else {
4109 if (!inRange) {
4110 return (FALSE);
4111 }
4112 }
4113 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4114 bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, kernel_policy->cond_local_prefix);
4115 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4116 if (inSubnet) {
4117 return (FALSE);
4118 }
4119 } else {
4120 if (!inSubnet) {
4121 return (FALSE);
4122 }
4123 }
4124 }
4125 }
4126
4127 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4128 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4129 bool inRange = necp_is_addr_in_range((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, (struct sockaddr *)&kernel_policy->cond_remote_end);
4130 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4131 if (inRange) {
4132 return (FALSE);
4133 }
4134 } else {
4135 if (!inRange) {
4136 return (FALSE);
4137 }
4138 }
4139 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4140 bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, kernel_policy->cond_remote_prefix);
4141 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4142 if (inSubnet) {
4143 return (FALSE);
4144 }
4145 } else {
4146 if (!inSubnet) {
4147 return (FALSE);
4148 }
4149 }
4150 }
4151 }
4152
4153 return (TRUE);
4154 }
4155
4156 static inline u_int32_t
4157 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
4158 {
4159 return (net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount));
4160 }
4161
4162 #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)
4163 static void
4164 necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, struct necp_socket_info *info)
4165 {
4166 struct socket *so = NULL;
4167
4168 memset(info, 0, sizeof(struct necp_socket_info));
4169
4170 so = inp->inp_socket;
4171
4172 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
4173 info->pid = ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
4174 }
4175
4176 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID) {
4177 info->uid = kauth_cred_getuid(so->so_cred);
4178 }
4179
4180 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4181 info->traffic_class = so->so_traffic_class;
4182 }
4183
4184 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4185 if (inp->inp_ip_p) {
4186 info->protocol = inp->inp_ip_p;
4187 } else {
4188 info->protocol = SOCK_PROTO(so);
4189 }
4190 }
4191
4192 if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4193 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
4194 if (existing_mapping) {
4195 info->application_id = existing_mapping->id;
4196 }
4197
4198 if (!(so->so_flags & SOF_DELEGATED)) {
4199 info->real_application_id = info->application_id;
4200 } else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4201 struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
4202 if (real_existing_mapping) {
4203 info->real_application_id = real_existing_mapping->id;
4204 }
4205 }
4206
4207 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
4208 info->cred_result = priv_check_cred(so->so_cred, PRIV_NET_PRIVILEGED_NECP_MATCH, 0);
4209 }
4210 }
4211
4212 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
4213 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
4214 if (existing_mapping) {
4215 info->account_id = existing_mapping->id;
4216 }
4217 }
4218
4219 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
4220 info->domain = inp->inp_necp_attributes.inp_domain;
4221 }
4222
4223 if (override_bound_interface) {
4224 info->bound_interface_index = override_bound_interface;
4225 } else {
4226 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
4227 info->bound_interface_index = inp->inp_boundifp->if_index;
4228 }
4229 }
4230
4231 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) {
4232 if (inp->inp_vflag & INP_IPV4) {
4233 if (override_local_addr) {
4234 memcpy(&info->local_addr, override_local_addr, override_local_addr->sa_len);
4235 } else {
4236 ((struct sockaddr_in *)&info->local_addr)->sin_family = AF_INET;
4237 ((struct sockaddr_in *)&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
4238 ((struct sockaddr_in *)&info->local_addr)->sin_port = inp->inp_lport;
4239 memcpy(&((struct sockaddr_in *)&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
4240 }
4241
4242 if (override_remote_addr) {
4243 memcpy(&info->remote_addr, override_remote_addr, override_remote_addr->sa_len);
4244 } else {
4245 ((struct sockaddr_in *)&info->remote_addr)->sin_family = AF_INET;
4246 ((struct sockaddr_in *)&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
4247 ((struct sockaddr_in *)&info->remote_addr)->sin_port = inp->inp_fport;
4248 memcpy(&((struct sockaddr_in *)&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
4249 }
4250 } else if (inp->inp_vflag & INP_IPV6) {
4251 if (override_local_addr) {
4252 memcpy(&info->local_addr, override_local_addr, override_local_addr->sa_len);
4253 } else {
4254 ((struct sockaddr_in6 *)&info->local_addr)->sin6_family = AF_INET6;
4255 ((struct sockaddr_in6 *)&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
4256 ((struct sockaddr_in6 *)&info->local_addr)->sin6_port = inp->inp_lport;
4257 memcpy(&((struct sockaddr_in6 *)&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
4258 }
4259
4260 if (override_remote_addr) {
4261 memcpy(&info->remote_addr, override_remote_addr, override_remote_addr->sa_len);
4262 } else {
4263 ((struct sockaddr_in6 *)&info->remote_addr)->sin6_family = AF_INET6;
4264 ((struct sockaddr_in6 *)&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
4265 ((struct sockaddr_in6 *)&info->remote_addr)->sin6_port = inp->inp_fport;
4266 memcpy(&((struct sockaddr_in6 *)&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
4267 }
4268 }
4269 }
4270 }
4271
4272 static inline struct necp_kernel_socket_policy *
4273 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, necp_kernel_policy_result *return_service_action, necp_kernel_policy_service *return_service)
4274 {
4275 struct necp_kernel_socket_policy *matched_policy = NULL;
4276 u_int32_t skip_order = 0;
4277 u_int32_t skip_session_order = 0;
4278 int i;
4279
4280 // Pre-process domain for quick matching
4281 struct substring domain_substring = necp_trim_dots_and_stars(info->domain, info->domain ? strlen(info->domain) : 0);
4282 u_int8_t domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
4283
4284 if (return_filter) {
4285 *return_filter = 0;
4286 }
4287
4288 if (return_service_action) {
4289 *return_service_action = 0;
4290 }
4291
4292 if (return_service) {
4293 return_service->identifier = 0;
4294 return_service->data = 0;
4295 }
4296
4297 if (policy_search_array != NULL) {
4298 for (i = 0; policy_search_array[i] != NULL; i++) {
4299 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
4300 // We've hit a drop all rule
4301 break;
4302 }
4303 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
4304 // Done skipping
4305 skip_order = 0;
4306 skip_session_order = 0;
4307 }
4308 if (skip_order) {
4309 if (policy_search_array[i]->order < skip_order) {
4310 // Skip this policy
4311 continue;
4312 } else {
4313 // Done skipping
4314 skip_order = 0;
4315 skip_session_order = 0;
4316 }
4317 } else if (skip_session_order) {
4318 // Skip this policy
4319 continue;
4320 }
4321 if (necp_socket_check_policy(policy_search_array[i], info->application_id, info->real_application_id, info->cred_result, info->account_id, domain_substring, domain_dot_count, info->pid, info->uid, info->bound_interface_index, info->traffic_class, info->protocol, &info->local_addr, &info->remote_addr)) {
4322 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
4323 if (return_filter && *return_filter == 0) {
4324 *return_filter = policy_search_array[i]->result_parameter.filter_control_unit;
4325 if (necp_debug > 1) {
4326 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);
4327 }
4328 }
4329 continue;
4330 } else if (necp_kernel_socket_result_is_service_type(policy_search_array[i])) {
4331 if (return_service_action && *return_service_action == 0) {
4332 *return_service_action = policy_search_array[i]->result;
4333 if (necp_debug > 1) {
4334 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);
4335 }
4336 }
4337 if (return_service && return_service->identifier == 0) {
4338 return_service->identifier = policy_search_array[i]->result_parameter.service.identifier;
4339 return_service->data = policy_search_array[i]->result_parameter.service.data;
4340 if (necp_debug > 1) {
4341 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);
4342 }
4343 }
4344 continue;
4345 }
4346
4347 // Passed all tests, found a match
4348 matched_policy = policy_search_array[i];
4349 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
4350 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
4351 skip_session_order = policy_search_array[i]->session_order + 1;
4352 continue;
4353 }
4354 break;
4355 }
4356 }
4357 }
4358
4359 return (matched_policy);
4360 }
4361
4362 static bool
4363 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
4364 {
4365 bool found_match = FALSE;
4366 errno_t result = 0;
4367 ifaddr_t *addresses = NULL;
4368 union necp_sockaddr_union address_storage;
4369 int i;
4370 int family = AF_INET;
4371 ifnet_t interface = ifindex2ifnet[interface_index];
4372
4373 if (inp == NULL || interface == NULL) {
4374 return (FALSE);
4375 }
4376
4377 if (inp->inp_vflag & INP_IPV4) {
4378 family = AF_INET;
4379 } else if (inp->inp_vflag & INP_IPV6) {
4380 family = AF_INET6;
4381 }
4382
4383 result = ifnet_get_address_list_family(interface, &addresses, family);
4384 if (result != 0) {
4385 NECPLOG(LOG_ERR, "Failed to get address list for %s%d", ifnet_name(interface), ifnet_unit(interface));
4386 return (FALSE);
4387 }
4388
4389 for (i = 0; addresses[i] != NULL; i++) {
4390 if (ifaddr_address(addresses[i], &address_storage.sa, sizeof(address_storage)) == 0) {
4391 if (family == AF_INET) {
4392 if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
4393 found_match = TRUE;
4394 goto done;
4395 }
4396 } else if (family == AF_INET6) {
4397 if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
4398 found_match = TRUE;
4399 goto done;
4400 }
4401 }
4402 }
4403 }
4404
4405 done:
4406 ifnet_free_address_list(addresses);
4407 addresses = NULL;
4408 return (found_match);
4409 }
4410
4411 static inline bool
4412 necp_socket_is_connected(struct inpcb *inp)
4413 {
4414 return (inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING));
4415 }
4416
4417 necp_kernel_policy_id
4418 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
4419 {
4420 struct socket *so = NULL;
4421 necp_kernel_policy_filter filter_control_unit = 0;
4422 struct necp_kernel_socket_policy *matched_policy = NULL;
4423 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4424 necp_kernel_policy_result service_action = 0;
4425 necp_kernel_policy_service service = { 0, 0 };
4426
4427 struct necp_socket_info info;
4428
4429 if (inp == NULL) {
4430 return (NECP_KERNEL_POLICY_ID_NONE);
4431 }
4432
4433 so = inp->inp_socket;
4434
4435 // Don't lock. Possible race condition, but we don't want the performance hit.
4436 if (necp_kernel_socket_policies_count == 0 ||
4437 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0)) {
4438 if (necp_drop_all_order > 0) {
4439 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4440 inp->inp_policyresult.policy_gencount = 0;
4441 inp->inp_policyresult.flowhash = 0;
4442 inp->inp_policyresult.results.filter_control_unit = 0;
4443 if (necp_pass_loopback > 0 &&
4444 necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL)) {
4445 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
4446 } else {
4447 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
4448 }
4449 }
4450 return (NECP_KERNEL_POLICY_ID_NONE);
4451 }
4452
4453 // Check for loopback exception
4454 if (necp_pass_loopback > 0 &&
4455 necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL)) {
4456 // Mark socket as a pass
4457 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4458 inp->inp_policyresult.policy_gencount = 0;
4459 inp->inp_policyresult.flowhash = 0;
4460 inp->inp_policyresult.results.filter_control_unit = 0;
4461 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
4462 return (NECP_KERNEL_POLICY_ID_NONE);
4463 }
4464
4465 // Lock
4466 lck_rw_lock_shared(&necp_kernel_policy_lock);
4467
4468 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, &info);
4469
4470 // Check info
4471 u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
4472 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
4473 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
4474 inp->inp_policyresult.flowhash == flowhash) {
4475 // If already matched this socket on this generation of table, skip
4476
4477 // Unlock
4478 lck_rw_done(&necp_kernel_policy_lock);
4479
4480 return (inp->inp_policyresult.policy_id);
4481 }
4482
4483 // Match socket to policy
4484 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, &service_action, &service);
4485 // If the socket matched a scoped service policy, mark as Drop if not registered.
4486 // This covers the cases in which a service is required (on demand) but hasn't started yet.
4487 if ((service_action == NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED ||
4488 service_action == NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED) &&
4489 service.identifier != 0 &&
4490 service.identifier != NECP_NULL_SERVICE_ID) {
4491 bool service_is_registered = FALSE;
4492 struct necp_service_registration *service_registration = NULL;
4493 LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
4494 if (service.identifier == service_registration->service_id) {
4495 service_is_registered = TRUE;
4496 break;
4497 }
4498 }
4499 if (!service_is_registered) {
4500 // Mark socket as a drop if service is not registered
4501 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4502 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
4503 inp->inp_policyresult.flowhash = flowhash;
4504 inp->inp_policyresult.results.filter_control_unit = 0;
4505 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
4506
4507 if (necp_debug > 1) {
4508 NECPLOG(LOG_DEBUG, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because service is not registered", info.bound_interface_index, info.protocol);
4509 }
4510
4511 // Unlock
4512 lck_rw_done(&necp_kernel_policy_lock);
4513 return (NECP_KERNEL_POLICY_ID_NONE);
4514 }
4515 }
4516 if (matched_policy) {
4517 matched_policy_id = matched_policy->id;
4518 inp->inp_policyresult.policy_id = matched_policy->id;
4519 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
4520 inp->inp_policyresult.flowhash = flowhash;
4521 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
4522 inp->inp_policyresult.results.result = matched_policy->result;
4523 memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
4524
4525 if (necp_socket_is_connected(inp) &&
4526 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
4527 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
4528 if (necp_debug) {
4529 NECPLOG(LOG_DEBUG, "Marking socket in state %d as defunct", so->so_state);
4530 }
4531 sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
4532 }
4533
4534 if (necp_debug > 1) {
4535 NECPLOG(LOG_DEBUG, "Socket Policy: (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d", info.bound_interface_index, info.protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index);
4536 }
4537 } else if (necp_drop_all_order > 0) {
4538 // Mark socket as a drop if set
4539 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4540 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
4541 inp->inp_policyresult.flowhash = flowhash;
4542 inp->inp_policyresult.results.filter_control_unit = 0;
4543 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
4544 } else {
4545 // Mark non-matching socket so we don't re-check it
4546 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4547 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
4548 inp->inp_policyresult.flowhash = flowhash;
4549 inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
4550 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
4551 }
4552
4553 // Unlock
4554 lck_rw_done(&necp_kernel_policy_lock);
4555
4556 return (matched_policy_id);
4557 }
4558
4559 static bool
4560 necp_ip_output_check_policy(struct necp_kernel_ip_output_policy *kernel_policy, necp_kernel_policy_id socket_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)
4561 {
4562 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
4563 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
4564 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
4565 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
4566 if (bound_interface_index == cond_bound_interface_index) {
4567 // No match, matches forbidden interface
4568 return (FALSE);
4569 }
4570 } else {
4571 if (bound_interface_index != cond_bound_interface_index) {
4572 // No match, does not match required interface
4573 return (FALSE);
4574 }
4575 }
4576 } else {
4577 if (bound_interface_index != 0) {
4578 // No match, requires a non-bound packet
4579 return (FALSE);
4580 }
4581 }
4582 }
4583
4584 if (kernel_policy->condition_mask == 0) {
4585 return (TRUE);
4586 }
4587
4588 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
4589 if (socket_policy_id != kernel_policy->cond_policy_id) {
4590 // No match, does not match required id
4591 return (FALSE);
4592 }
4593 }
4594
4595 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
4596 if (last_interface_index != kernel_policy->cond_last_interface_index) {
4597 return (FALSE);
4598 }
4599 }
4600
4601 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4602 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4603 if (protocol == kernel_policy->cond_protocol) {
4604 // No match, matches forbidden protocol
4605 return (FALSE);
4606 }
4607 } else {
4608 if (protocol != kernel_policy->cond_protocol) {
4609 // No match, does not match required protocol
4610 return (FALSE);
4611 }
4612 }
4613 }
4614
4615 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4616 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4617 bool inRange = necp_is_addr_in_range((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, (struct sockaddr *)&kernel_policy->cond_local_end);
4618 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4619 if (inRange) {
4620 return (FALSE);
4621 }
4622 } else {
4623 if (!inRange) {
4624 return (FALSE);
4625 }
4626 }
4627 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4628 bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, kernel_policy->cond_local_prefix);
4629 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4630 if (inSubnet) {
4631 return (FALSE);
4632 }
4633 } else {
4634 if (!inSubnet) {
4635 return (FALSE);
4636 }
4637 }
4638 }
4639 }
4640
4641 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4642 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4643 bool inRange = necp_is_addr_in_range((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, (struct sockaddr *)&kernel_policy->cond_remote_end);
4644 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4645 if (inRange) {
4646 return (FALSE);
4647 }
4648 } else {
4649 if (!inRange) {
4650 return (FALSE);
4651 }
4652 }
4653 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4654 bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, kernel_policy->cond_remote_prefix);
4655 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4656 if (inSubnet) {
4657 return (FALSE);
4658 }
4659 } else {
4660 if (!inSubnet) {
4661 return (FALSE);
4662 }
4663 }
4664 }
4665 }
4666
4667 return (TRUE);
4668 }
4669
4670 static inline struct necp_kernel_ip_output_policy *
4671 necp_ip_output_find_policy_match_locked(necp_kernel_policy_id socket_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)
4672 {
4673 u_int32_t skip_order = 0;
4674 u_int32_t skip_session_order = 0;
4675 int i;
4676 struct necp_kernel_ip_output_policy *matched_policy = NULL;
4677 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)];
4678 if (policy_search_array != NULL) {
4679 for (i = 0; policy_search_array[i] != NULL; i++) {
4680 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
4681 // We've hit a drop all rule
4682 break;
4683 }
4684 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
4685 // Done skipping
4686 skip_order = 0;
4687 skip_session_order = 0;
4688 }
4689 if (skip_order) {
4690 if (policy_search_array[i]->order < skip_order) {
4691 // Skip this policy
4692 continue;
4693 } else {
4694 // Done skipping
4695 skip_order = 0;
4696 skip_session_order = 0;
4697 }
4698 } else if (skip_session_order) {
4699 // Skip this policy
4700 continue;
4701 }
4702 if (necp_ip_output_check_policy(policy_search_array[i], socket_policy_id, bound_interface_index, last_interface_index, protocol, local_addr, remote_addr)) {
4703 // Passed all tests, found a match
4704 matched_policy = policy_search_array[i];
4705
4706 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
4707 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
4708 skip_session_order = policy_search_array[i]->session_order + 1;
4709 continue;
4710 }
4711
4712 break;
4713 }
4714 }
4715 }
4716
4717 return (matched_policy);
4718 }
4719
4720 necp_kernel_policy_id
4721 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
4722 {
4723 struct ip *ip = NULL;
4724 int hlen = sizeof(struct ip);
4725 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4726 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4727 struct necp_kernel_ip_output_policy *matched_policy = NULL;
4728 u_int16_t protocol = 0;
4729 u_int32_t bound_interface_index = 0;
4730 u_int32_t last_interface_index = 0;
4731 union necp_sockaddr_union local_addr;
4732 union necp_sockaddr_union remote_addr;
4733
4734 if (result) {
4735 *result = 0;
4736 }
4737
4738 if (result_parameter) {
4739 memset(result_parameter, 0, sizeof(*result_parameter));
4740 }
4741
4742 if (packet == NULL) {
4743 return (NECP_KERNEL_POLICY_ID_NONE);
4744 }
4745
4746 socket_policy_id = necp_get_policy_id_from_packet(packet);
4747
4748 // Exit early for an empty list
4749 // Don't lock. Possible race condition, but we don't want the performance hit.
4750 if (necp_kernel_ip_output_policies_count == 0 ||
4751 ((socket_policy_id == NECP_KERNEL_POLICY_ID_NONE) && necp_kernel_ip_output_policies_non_id_count == 0)) {
4752 if (necp_drop_all_order > 0) {
4753 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4754 if (result) {
4755 if ((necp_pass_loopback > 0 &&
4756 necp_is_loopback(NULL, NULL, NULL, packet)) ||
4757 (necp_pass_keepalives > 0 &&
4758 necp_get_is_keepalive_from_packet(packet))) {
4759 *result = NECP_KERNEL_POLICY_RESULT_PASS;
4760 } else {
4761 *result = NECP_KERNEL_POLICY_RESULT_DROP;
4762 }
4763 }
4764 }
4765
4766 return (matched_policy_id);
4767 }
4768
4769 // Check for loopback exception
4770 if ((necp_pass_loopback > 0 &&
4771 necp_is_loopback(NULL, NULL, NULL, packet)) ||
4772 (necp_pass_keepalives > 0 &&
4773 necp_get_is_keepalive_from_packet(packet))) {
4774 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4775 if (result) {
4776 *result = NECP_KERNEL_POLICY_RESULT_PASS;
4777 }
4778 return (matched_policy_id);
4779 }
4780
4781 last_interface_index = necp_get_last_interface_index_from_packet(packet);
4782
4783 // Process packet to get relevant fields
4784 ip = mtod(packet, struct ip *);
4785 #ifdef _IP_VHL
4786 hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
4787 #else
4788 hlen = ip->ip_hl << 2;
4789 #endif
4790
4791 protocol = ip->ip_p;
4792
4793 if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
4794 (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
4795 ipoa->ipoa_boundif != IFSCOPE_NONE) {
4796 bound_interface_index = ipoa->ipoa_boundif;
4797 }
4798
4799 local_addr.sin.sin_family = AF_INET;
4800 local_addr.sin.sin_len = sizeof(struct sockaddr_in);
4801 memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
4802
4803 remote_addr.sin.sin_family = AF_INET;
4804 remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
4805 memcpy(&((struct sockaddr_in *)&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
4806
4807 switch (protocol) {
4808 case IPPROTO_TCP: {
4809 struct tcphdr th;
4810 if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
4811 m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
4812 ((struct sockaddr_in *)&local_addr)->sin_port = th.th_sport;
4813 ((struct sockaddr_in *)&remote_addr)->sin_port = th.th_dport;
4814 }
4815 break;
4816 }
4817 case IPPROTO_UDP: {
4818 struct udphdr uh;
4819 if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
4820 m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
4821 ((struct sockaddr_in *)&local_addr)->sin_port = uh.uh_sport;
4822 ((struct sockaddr_in *)&remote_addr)->sin_port = uh.uh_dport;
4823 }
4824 break;
4825 }
4826 default: {
4827 ((struct sockaddr_in *)&local_addr)->sin_port = 0;
4828 ((struct sockaddr_in *)&remote_addr)->sin_port = 0;
4829 break;
4830 }
4831 }
4832
4833 // Match packet to policy
4834 lck_rw_lock_shared(&necp_kernel_policy_lock);
4835 matched_policy = necp_ip_output_find_policy_match_locked(socket_policy_id, bound_interface_index, last_interface_index, protocol, &local_addr, &remote_addr);
4836 if (matched_policy) {
4837 matched_policy_id = matched_policy->id;
4838 if (result) {
4839 *result = matched_policy->result;
4840 }
4841
4842 if (result_parameter) {
4843 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
4844 }
4845
4846 if (necp_debug > 1) {
4847 NECPLOG(LOG_DEBUG, "IP Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d", socket_policy_id, bound_interface_index, last_interface_index, protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index);
4848 }
4849 } else if (necp_drop_all_order > 0) {
4850 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4851 if (result) {
4852 *result = NECP_KERNEL_POLICY_RESULT_DROP;
4853 }
4854 }
4855
4856 lck_rw_done(&necp_kernel_policy_lock);
4857
4858 return (matched_policy_id);
4859 }
4860
4861 necp_kernel_policy_id
4862 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
4863 {
4864 struct ip6_hdr *ip6 = NULL;
4865 int next = -1;
4866 int offset = 0;
4867 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4868 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
4869 struct necp_kernel_ip_output_policy *matched_policy = NULL;
4870 u_int16_t protocol = 0;
4871 u_int32_t bound_interface_index = 0;
4872 u_int32_t last_interface_index = 0;
4873 union necp_sockaddr_union local_addr;
4874 union necp_sockaddr_union remote_addr;
4875
4876 if (result) {
4877 *result = 0;
4878 }
4879
4880 if (result_parameter) {
4881 memset(result_parameter, 0, sizeof(*result_parameter));
4882 }
4883
4884 if (packet == NULL) {
4885 return (NECP_KERNEL_POLICY_ID_NONE);
4886 }
4887
4888 socket_policy_id = necp_get_policy_id_from_packet(packet);
4889
4890 // Exit early for an empty list
4891 // Don't lock. Possible race condition, but we don't want the performance hit.
4892 if (necp_kernel_ip_output_policies_count == 0 ||
4893 ((socket_policy_id == NECP_KERNEL_POLICY_ID_NONE) && necp_kernel_ip_output_policies_non_id_count == 0)) {
4894 if (necp_drop_all_order > 0) {
4895 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4896 if (result) {
4897 if ((necp_pass_loopback > 0 &&
4898 necp_is_loopback(NULL, NULL, NULL, packet)) ||
4899 (necp_pass_keepalives > 0 &&
4900 necp_get_is_keepalive_from_packet(packet))) {
4901 *result = NECP_KERNEL_POLICY_RESULT_PASS;
4902 } else {
4903 *result = NECP_KERNEL_POLICY_RESULT_DROP;
4904 }
4905 }
4906 }
4907
4908 return (matched_policy_id);
4909 }
4910
4911 // Check for loopback exception
4912 if ((necp_pass_loopback > 0 &&
4913 necp_is_loopback(NULL, NULL, NULL, packet)) ||
4914 (necp_pass_keepalives > 0 &&
4915 necp_get_is_keepalive_from_packet(packet))) {
4916 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4917 if (result) {
4918 *result = NECP_KERNEL_POLICY_RESULT_PASS;
4919 }
4920 return (matched_policy_id);
4921 }
4922
4923 last_interface_index = necp_get_last_interface_index_from_packet(packet);
4924
4925 // Process packet to get relevant fields
4926 ip6 = mtod(packet, struct ip6_hdr *);
4927
4928 if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
4929 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
4930 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
4931 bound_interface_index = ip6oa->ip6oa_boundif;
4932 }
4933
4934 ((struct sockaddr_in6 *)&local_addr)->sin6_family = AF_INET6;
4935 ((struct sockaddr_in6 *)&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
4936 memcpy(&((struct sockaddr_in6 *)&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
4937
4938 ((struct sockaddr_in6 *)&remote_addr)->sin6_family = AF_INET6;
4939 ((struct sockaddr_in6 *)&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
4940 memcpy(&((struct sockaddr_in6 *)&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
4941
4942 offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
4943 if (offset >= 0 && packet->m_pkthdr.len >= offset) {
4944 protocol = next;
4945 switch (protocol) {
4946 case IPPROTO_TCP: {
4947 struct tcphdr th;
4948 if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
4949 m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
4950 ((struct sockaddr_in6 *)&local_addr)->sin6_port = th.th_sport;
4951 ((struct sockaddr_in6 *)&remote_addr)->sin6_port = th.th_dport;
4952 }
4953 break;
4954 }
4955 case IPPROTO_UDP: {
4956 struct udphdr uh;
4957 if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
4958 m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
4959 ((struct sockaddr_in6 *)&local_addr)->sin6_port = uh.uh_sport;
4960 ((struct sockaddr_in6 *)&remote_addr)->sin6_port = uh.uh_dport;
4961 }
4962 break;
4963 }
4964 default: {
4965 ((struct sockaddr_in6 *)&local_addr)->sin6_port = 0;
4966 ((struct sockaddr_in6 *)&remote_addr)->sin6_port = 0;
4967 break;
4968 }
4969 }
4970 }
4971
4972 // Match packet to policy
4973 lck_rw_lock_shared(&necp_kernel_policy_lock);
4974 matched_policy = necp_ip_output_find_policy_match_locked(socket_policy_id, bound_interface_index, last_interface_index, protocol, &local_addr, &remote_addr);
4975 if (matched_policy) {
4976 matched_policy_id = matched_policy->id;
4977 if (result) {
4978 *result = matched_policy->result;
4979 }
4980
4981 if (result_parameter) {
4982 memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
4983 }
4984
4985 if (necp_debug > 1) {
4986 NECPLOG(LOG_DEBUG, "IP6 Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d", socket_policy_id, bound_interface_index, last_interface_index, protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index);
4987 }
4988 } else if (necp_drop_all_order > 0) {
4989 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
4990 if (result) {
4991 *result = NECP_KERNEL_POLICY_RESULT_DROP;
4992 }
4993 }
4994
4995 lck_rw_done(&necp_kernel_policy_lock);
4996
4997 return (matched_policy_id);
4998 }
4999
5000 // Utilities
5001 static bool
5002 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
5003 {
5004 int cmp = 0;
5005
5006 if (addr == NULL || range_start == NULL || range_end == NULL) {
5007 return (FALSE);
5008 }
5009
5010 /* Must be greater than or equal to start */
5011 cmp = necp_addr_compare(addr, range_start, 1);
5012 if (cmp != 0 && cmp != 1) {
5013 return (FALSE);
5014 }
5015
5016 /* Must be less than or equal to end */
5017 cmp = necp_addr_compare(addr, range_end, 1);
5018 if (cmp != 0 && cmp != -1) {
5019 return (FALSE);
5020 }
5021
5022 return (TRUE);
5023 }
5024
5025 static bool
5026 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
5027 {
5028 int cmp = 0;
5029
5030 if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
5031 return (FALSE);
5032 }
5033
5034 /* Must be greater than or equal to start */
5035 cmp = necp_addr_compare(inner_range_start, range_start, 1);
5036 if (cmp != 0 && cmp != 1) {
5037 return (FALSE);
5038 }
5039
5040 /* Must be less than or equal to end */
5041 cmp = necp_addr_compare(inner_range_end, range_end, 1);
5042 if (cmp != 0 && cmp != -1) {
5043 return (FALSE);
5044 }
5045
5046 return (TRUE);
5047 }
5048
5049 static bool
5050 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
5051 {
5052 if (addr == NULL || subnet_addr == NULL) {
5053 return (FALSE);
5054 }
5055
5056 if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
5057 return (FALSE);
5058 }
5059
5060 switch (addr->sa_family) {
5061 case AF_INET: {
5062 if (satosin(subnet_addr)->sin_port != 0 &&
5063 satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
5064 return (FALSE);
5065 }
5066 return (necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix));
5067 }
5068 case AF_INET6: {
5069 if (satosin6(subnet_addr)->sin6_port != 0 &&
5070 satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
5071 return (FALSE);
5072 }
5073 if (satosin6(addr)->sin6_scope_id &&
5074 satosin6(subnet_addr)->sin6_scope_id &&
5075 satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
5076 return (FALSE);
5077 }
5078 return (necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix));
5079 }
5080 default: {
5081 return (FALSE);
5082 }
5083 }
5084
5085 return (FALSE);
5086 }
5087
5088 /*
5089 * Return values:
5090 * -1: sa1 < sa2
5091 * 0: sa1 == sa2
5092 * 1: sa1 > sa2
5093 * 2: Not comparable or error
5094 */
5095 static int
5096 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
5097 {
5098 int result = 0;
5099 int port_result = 0;
5100
5101 if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
5102 return (2);
5103 }
5104
5105 if (sa1->sa_len == 0) {
5106 return (0);
5107 }
5108
5109 switch (sa1->sa_family) {
5110 case AF_INET: {
5111 if (sa1->sa_len != sizeof(struct sockaddr_in)) {
5112 return (2);
5113 }
5114
5115 result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
5116
5117 if (check_port) {
5118 if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
5119 port_result = -1;
5120 } else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
5121 port_result = 1;
5122 }
5123
5124 if (result == 0) {
5125 result = port_result;
5126 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
5127 return (2);
5128 }
5129 }
5130
5131 break;
5132 }
5133 case AF_INET6: {
5134 if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
5135 return (2);
5136 }
5137
5138 if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
5139 return (2);
5140 }
5141
5142 result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
5143
5144 if (check_port) {
5145 if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
5146 port_result = -1;
5147 } else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
5148 port_result = 1;
5149 }
5150
5151 if (result == 0) {
5152 result = port_result;
5153 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
5154 return (2);
5155 }
5156 }
5157
5158 break;
5159 }
5160 default: {
5161 result = memcmp(sa1, sa2, sa1->sa_len);
5162 break;
5163 }
5164 }
5165
5166 if (result < 0) {
5167 result = (-1);
5168 } else if (result > 0) {
5169 result = (1);
5170 }
5171
5172 return (result);
5173 }
5174
5175 static bool
5176 necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits)
5177 {
5178 u_int8_t mask;
5179
5180 /* Handle null pointers */
5181 if (p1 == NULL || p2 == NULL) {
5182 return (p1 == p2);
5183 }
5184
5185 while (bits >= 8) {
5186 if (*p1++ != *p2++) {
5187 return (FALSE);
5188 }
5189 bits -= 8;
5190 }
5191
5192 if (bits > 0) {
5193 mask = ~((1<<(8-bits))-1);
5194 if ((*p1 & mask) != (*p2 & mask)) {
5195 return (FALSE);
5196 }
5197 }
5198 return (TRUE);
5199 }
5200
5201 // Socket operations
5202 #define NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH 253
5203
5204 static bool
5205 necp_set_socket_attribute(u_int8_t *buffer, size_t buffer_length, u_int8_t type, char **buffer_p)
5206 {
5207 int error = 0;
5208 int cursor = 0;
5209 size_t string_size = 0;
5210 char *local_string = NULL;
5211 u_int8_t *value = NULL;
5212
5213 cursor = necp_buffer_find_tlv(buffer, buffer_length, 0, type, 0);
5214 if (cursor < 0) {
5215 // This will clear out the parameter
5216 goto done;
5217 }
5218
5219 string_size = necp_buffer_get_tlv_length(buffer, cursor);
5220 if (string_size == 0 || string_size > NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) {
5221 // This will clear out the parameter
5222 goto done;
5223 }
5224
5225 MALLOC(local_string, char *, string_size + 1, M_NECP, M_WAITOK);
5226 if (local_string == NULL) {
5227 NECPLOG(LOG_ERR, "Failed to allocate a socket attribute buffer (size %d)", string_size);
5228 goto fail;
5229 }
5230
5231 value = necp_buffer_get_tlv_value(buffer, cursor, NULL);
5232 if (value == NULL) {
5233 NECPLOG0(LOG_ERR, "Failed to get socket attribute");
5234 goto fail;
5235 }
5236
5237 memcpy(local_string, value, string_size);
5238 local_string[string_size] = 0;
5239
5240 done:
5241 if (*buffer_p != NULL) {
5242 FREE(*buffer_p, M_NECP);
5243 *buffer_p = NULL;
5244 }
5245
5246 *buffer_p = local_string;
5247 return (0);
5248 fail:
5249 if (local_string != NULL) {
5250 FREE(local_string, M_NECP);
5251 }
5252 return (error);
5253 }
5254
5255 errno_t
5256 necp_set_socket_attributes(struct socket *so, struct sockopt *sopt)
5257 {
5258 int error = 0;
5259 u_int8_t *buffer = NULL;
5260 struct inpcb *inp = sotoinpcb(so);
5261
5262 size_t valsize = sopt->sopt_valsize;
5263 if (valsize == 0 ||
5264 valsize > ((sizeof(u_int8_t) + sizeof(size_t) + NECP_MAX_SOCKET_ATTRIBUTE_STRING_LENGTH) * 2)) {
5265 goto done;
5266 }
5267
5268 MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK);
5269 if (buffer == NULL) {
5270 goto done;
5271 }
5272
5273 error = sooptcopyin(sopt, buffer, valsize, 0);
5274 if (error) {
5275 goto done;
5276 }
5277
5278 error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_DOMAIN, &inp->inp_necp_attributes.inp_domain);
5279 if (error) {
5280 NECPLOG0(LOG_ERR, "Could not set domain TLV for socket attributes");
5281 goto done;
5282 }
5283
5284 error = necp_set_socket_attribute(buffer, valsize, NECP_TLV_ATTRIBUTE_ACCOUNT, &inp->inp_necp_attributes.inp_account);
5285 if (error) {
5286 NECPLOG0(LOG_ERR, "Could not set account TLV for socket attributes");
5287 goto done;
5288 }
5289
5290 if (necp_debug) {
5291 NECPLOG(LOG_DEBUG, "Set on socket: Domain %s, Account %s", inp->inp_necp_attributes.inp_domain, inp->inp_necp_attributes.inp_account);
5292 }
5293 done:
5294 if (buffer != NULL) {
5295 FREE(buffer, M_NECP);
5296 }
5297
5298 return (error);
5299 }
5300
5301 errno_t
5302 necp_get_socket_attributes(struct socket *so, struct sockopt *sopt)
5303 {
5304 int error = 0;
5305 u_int8_t *buffer = NULL;
5306 u_int8_t *cursor = NULL;
5307 size_t valsize = 0;
5308 struct inpcb *inp = sotoinpcb(so);
5309
5310 if (inp->inp_necp_attributes.inp_domain != NULL) {
5311 valsize += sizeof(u_int8_t) + sizeof(size_t) + strlen(inp->inp_necp_attributes.inp_domain);
5312 }
5313 if (inp->inp_necp_attributes.inp_account != NULL) {
5314 valsize += sizeof(u_int8_t) + sizeof(size_t) + strlen(inp->inp_necp_attributes.inp_account);
5315 }
5316 if (valsize == 0) {
5317 goto done;
5318 }
5319
5320 MALLOC(buffer, u_int8_t *, valsize, M_NECP, M_WAITOK);
5321 if (buffer == NULL) {
5322 goto done;
5323 }
5324
5325 cursor = buffer;
5326 if (inp->inp_necp_attributes.inp_domain != NULL) {
5327 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_DOMAIN, strlen(inp->inp_necp_attributes.inp_domain), inp->inp_necp_attributes.inp_domain);
5328 }
5329
5330 if (inp->inp_necp_attributes.inp_account != NULL) {
5331 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_ATTRIBUTE_ACCOUNT, strlen(inp->inp_necp_attributes.inp_account), inp->inp_necp_attributes.inp_account);
5332 }
5333
5334 error = sooptcopyout(sopt, buffer, valsize);
5335 if (error) {
5336 goto done;
5337 }
5338 done:
5339 if (buffer != NULL) {
5340 FREE(buffer, M_NECP);
5341 }
5342
5343 return (error);
5344 }
5345
5346 static bool
5347 necp_socket_is_allowed_to_send_recv_internal(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, ifnet_t interface, necp_kernel_policy_id *return_policy_id)
5348 {
5349 u_int32_t verifyifindex = interface ? interface->if_index : 0;
5350 bool allowed_to_receive = TRUE;
5351 struct necp_socket_info info;
5352 u_int32_t flowhash = 0;
5353 necp_kernel_policy_result service_action = 0;
5354 necp_kernel_policy_service service = { 0, 0 };
5355
5356 if (return_policy_id) {
5357 *return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
5358 }
5359
5360 if (inp == NULL) {
5361 goto done;
5362 }
5363
5364 // Don't lock. Possible race condition, but we don't want the performance hit.
5365 if (necp_kernel_socket_policies_count == 0 ||
5366 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0)) {
5367 if (necp_drop_all_order > 0) {
5368 if (necp_pass_loopback > 0 &&
5369 necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL)) {
5370 allowed_to_receive = TRUE;
5371 } else {
5372 allowed_to_receive = FALSE;
5373 }
5374 }
5375 goto done;
5376 }
5377
5378 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
5379 if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
5380 bool policies_have_changed = FALSE;
5381 lck_rw_lock_shared(&necp_kernel_policy_lock);
5382 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
5383 policies_have_changed = TRUE;
5384 }
5385 lck_rw_done(&necp_kernel_policy_lock);
5386
5387 if (!policies_have_changed) {
5388 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
5389 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
5390 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && interface &&
5391 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
5392 allowed_to_receive = FALSE;
5393 } else if (return_policy_id) {
5394 *return_policy_id = inp->inp_policyresult.policy_id;
5395 }
5396 goto done;
5397 }
5398 }
5399
5400 // Check for loopback exception
5401 if (necp_pass_loopback > 0 &&
5402 necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL)) {
5403 allowed_to_receive = TRUE;
5404 goto done;
5405 }
5406
5407 // Actually calculate policy result
5408 lck_rw_lock_shared(&necp_kernel_policy_lock);
5409 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, &info);
5410
5411 flowhash = necp_socket_calc_flowhash_locked(&info);
5412 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
5413 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
5414 inp->inp_policyresult.flowhash == flowhash) {
5415 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
5416 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
5417 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && interface &&
5418 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
5419 allowed_to_receive = FALSE;
5420 } else if (return_policy_id) {
5421 *return_policy_id = inp->inp_policyresult.policy_id;
5422 }
5423 lck_rw_done(&necp_kernel_policy_lock);
5424 goto done;
5425 }
5426
5427 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, NULL, &service_action, &service);
5428 if (matched_policy != NULL) {
5429 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
5430 matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
5431 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && interface &&
5432 matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
5433 ((service_action == NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED ||
5434 service_action == NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED) &&
5435 service.identifier != 0 && service.identifier != NECP_NULL_SERVICE_ID)) {
5436 allowed_to_receive = FALSE;
5437 } else if (return_policy_id) {
5438 *return_policy_id = matched_policy->id;
5439 }
5440 lck_rw_done(&necp_kernel_policy_lock);
5441
5442 if (necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) {
5443 NECPLOG(LOG_DEBUG, "Socket Send/Recv Policy: Policy %d Allowed %d", return_policy_id ? *return_policy_id : 0, allowed_to_receive);
5444 }
5445 goto done;
5446 } else if (necp_drop_all_order > 0) {
5447 allowed_to_receive = FALSE;
5448 }
5449
5450 lck_rw_done(&necp_kernel_policy_lock);
5451
5452 done:
5453 return (allowed_to_receive);
5454 }
5455
5456 bool
5457 necp_socket_is_allowed_to_send_recv_v4(struct inpcb *inp, u_int16_t local_port, u_int16_t remote_port, struct in_addr *local_addr, struct in_addr *remote_addr, ifnet_t interface, necp_kernel_policy_id *return_policy_id)
5458 {
5459 struct sockaddr_in local;
5460 struct sockaddr_in remote;
5461 local.sin_family = remote.sin_family = AF_INET;
5462 local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
5463 local.sin_port = local_port;
5464 remote.sin_port = remote_port;
5465 memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
5466 memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
5467
5468 return (necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, interface, return_policy_id));
5469 }
5470
5471 bool
5472 necp_socket_is_allowed_to_send_recv_v6(struct inpcb *inp, u_int16_t local_port, u_int16_t remote_port, struct in6_addr *local_addr, struct in6_addr *remote_addr, ifnet_t interface, necp_kernel_policy_id *return_policy_id)
5473 {
5474 struct sockaddr_in6 local;
5475 struct sockaddr_in6 remote;
5476 local.sin6_family = remote.sin6_family = AF_INET6;
5477 local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
5478 local.sin6_port = local_port;
5479 remote.sin6_port = remote_port;
5480 memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
5481 memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
5482
5483 return (necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, interface, return_policy_id));
5484 }
5485
5486 bool
5487 necp_socket_is_allowed_to_send_recv(struct inpcb *inp, necp_kernel_policy_id *return_policy_id)
5488 {
5489 return (necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, NULL, return_policy_id));
5490 }
5491
5492 int
5493 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id)
5494 {
5495 if (packet == NULL || inp == NULL) {
5496 return (EINVAL);
5497 }
5498
5499 // Mark ID for Pass and IP Tunnel
5500 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
5501 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
5502 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
5503 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
5504 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
5505 } else {
5506 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
5507 }
5508 packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
5509
5510 return (0);
5511 }
5512
5513 int
5514 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
5515 {
5516 if (packet == NULL) {
5517 return (EINVAL);
5518 }
5519
5520 // Mark ID for Pass and IP Tunnel
5521 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
5522 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
5523 } else {
5524 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
5525 }
5526
5527 return (0);
5528 }
5529
5530 int
5531 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
5532 {
5533 if (packet == NULL) {
5534 return (EINVAL);
5535 }
5536
5537 // Mark ID for Pass and IP Tunnel
5538 if (interface != NULL) {
5539 packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
5540 }
5541
5542 return (0);
5543 }
5544
5545 int
5546 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
5547 {
5548 if (packet == NULL) {
5549 return (EINVAL);
5550 }
5551
5552 if (is_keepalive) {
5553 packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
5554 } else {
5555 packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
5556 }
5557
5558 return (0);
5559 }
5560
5561 necp_kernel_policy_id
5562 necp_get_policy_id_from_packet(struct mbuf *packet)
5563 {
5564 if (packet == NULL) {
5565 return (NECP_KERNEL_POLICY_ID_NONE);
5566 }
5567
5568 return (packet->m_pkthdr.necp_mtag.necp_policy_id);
5569 }
5570
5571 u_int32_t
5572 necp_get_last_interface_index_from_packet(struct mbuf *packet)
5573 {
5574 if (packet == NULL) {
5575 return (0);
5576 }
5577
5578 return (packet->m_pkthdr.necp_mtag.necp_last_interface_index);
5579 }
5580
5581 bool
5582 necp_get_is_keepalive_from_packet(struct mbuf *packet)
5583 {
5584 if (packet == NULL) {
5585 return (FALSE);
5586 }
5587
5588 return (packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE);
5589 }
5590
5591 u_int32_t
5592 necp_socket_get_content_filter_control_unit(struct socket *so)
5593 {
5594 struct inpcb *inp = sotoinpcb(so);
5595
5596 if (inp == NULL) {
5597 return (0);
5598 }
5599 return (inp->inp_policyresult.results.filter_control_unit);
5600 }
5601
5602 bool
5603 necp_socket_should_use_flow_divert(struct inpcb *inp)
5604 {
5605 if (inp == NULL) {
5606 return (FALSE);
5607 }
5608
5609 return (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT);
5610 }
5611
5612 u_int32_t
5613 necp_socket_get_flow_divert_control_unit(struct inpcb *inp)
5614 {
5615 if (inp == NULL) {
5616 return (0);
5617 }
5618
5619 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
5620 return (inp->inp_policyresult.results.result_parameter.flow_divert_control_unit);
5621 }
5622
5623 return (0);
5624 }
5625
5626 bool
5627 necp_socket_should_rescope(struct inpcb *inp)
5628 {
5629 if (inp == NULL) {
5630 return (FALSE);
5631 }
5632
5633 return (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED);
5634 }
5635
5636 u_int
5637 necp_socket_get_rescope_if_index(struct inpcb *inp)
5638 {
5639 if (inp == NULL) {
5640 return (0);
5641 }
5642
5643 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
5644 return (inp->inp_policyresult.results.result_parameter.scoped_interface_index);
5645 }
5646
5647 return (0);
5648 }
5649
5650 ifnet_t
5651 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
5652 {
5653 if (result_parameter == NULL) {
5654 return (NULL);
5655 }
5656
5657 return (ifindex2ifnet[result_parameter->tunnel_interface_index]);
5658 }
5659
5660 bool
5661 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
5662 {
5663 bool found_match = FALSE;
5664 errno_t result = 0;
5665 ifaddr_t *addresses = NULL;
5666 union necp_sockaddr_union address_storage;
5667 int i;
5668
5669 if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
5670 return (FALSE);
5671 }
5672
5673 result = ifnet_get_address_list_family(interface, &addresses, family);
5674 if (result != 0) {
5675 NECPLOG(LOG_ERR, "Failed to get address list for %s%d", ifnet_name(interface), ifnet_unit(interface));
5676 return (FALSE);
5677 }
5678
5679 for (i = 0; addresses[i] != NULL; i++) {
5680 ROUTE_RELEASE(new_route);
5681 if (ifaddr_address(addresses[i], &address_storage.sa, sizeof(address_storage)) == 0) {
5682 if (family == AF_INET) {
5683 struct ip *ip = mtod(packet, struct ip *);
5684 if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
5685 struct sockaddr_in *dst4 = (struct sockaddr_in *)(void *)&new_route->ro_dst;
5686 dst4->sin_family = AF_INET;
5687 dst4->sin_len = sizeof(struct sockaddr_in);
5688 dst4->sin_addr = ip->ip_dst;
5689 rtalloc_scoped(new_route, interface->if_index);
5690 if (!ROUTE_UNUSABLE(new_route)) {
5691 found_match = TRUE;
5692 goto done;
5693 }
5694 }
5695 } else if (family == AF_INET6) {
5696 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
5697 if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
5698 struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)(void *)&new_route->ro_dst;
5699 dst6->sin6_family = AF_INET6;
5700 dst6->sin6_len = sizeof(struct sockaddr_in6);
5701 dst6->sin6_addr = ip6->ip6_dst;
5702 rtalloc_scoped(new_route, interface->if_index);
5703 if (!ROUTE_UNUSABLE(new_route)) {
5704 found_match = TRUE;
5705 goto done;
5706 }
5707 }
5708 }
5709 }
5710 }
5711
5712 done:
5713 ifnet_free_address_list(addresses);
5714 addresses = NULL;
5715 return (found_match);
5716 }
5717
5718 static bool
5719 necp_addr_is_loopback(struct sockaddr *address)
5720 {
5721 if (address == NULL) {
5722 return (FALSE);
5723 }
5724
5725 if (address->sa_family == AF_INET) {
5726 return (ntohl(((struct sockaddr_in *)(void *)address)->sin_addr.s_addr) == INADDR_LOOPBACK);
5727 } else if (address->sa_family == AF_INET6) {
5728 return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)(void *)address)->sin6_addr);
5729 }
5730
5731 return (FALSE);
5732 }
5733
5734 static bool
5735 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet)
5736 {
5737 // Note: This function only checks for the loopback addresses.
5738 // In the future, we may want to expand to also allow any traffic
5739 // going through the loopback interface, but until then, this
5740 // check is cheaper.
5741
5742 if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
5743 return (TRUE);
5744 }
5745
5746 if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
5747 return (TRUE);
5748 }
5749
5750 if (inp != NULL) {
5751 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
5752 return (TRUE);
5753 }
5754 if (inp->inp_vflag & INP_IPV4) {
5755 if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
5756 ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
5757 return (TRUE);
5758 }
5759 } else if (inp->inp_vflag & INP_IPV6) {
5760 if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
5761 IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
5762 return (TRUE);
5763 }
5764 }
5765 }
5766
5767 if (packet != NULL) {
5768 struct ip *ip = mtod(packet, struct ip *);
5769 if (ip->ip_v == 4) {
5770 if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
5771 return (TRUE);
5772 }
5773 if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
5774 return (TRUE);
5775 }
5776 } else if (ip->ip_v == 6) {
5777 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
5778 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
5779 return (TRUE);
5780 }
5781 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
5782 return (TRUE);
5783 }
5784 }
5785 }
5786
5787 return (FALSE);
5788 }