/*
- * Copyright (c) 2013-2020 Apple Inc. All rights reserved.
+ * Copyright (c) 2013-2021 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <corecrypto/cchmac.h>
#include <corecrypto/ccsha2.h>
#include <os/refcnt.h>
+#include <mach-o/loader.h>
#include <net/network_agent.h>
#include <net/necp.h>
#include <netinet/flow_divert_proto.h>
u_int32_t necp_drop_all_order = 0;
u_int32_t necp_drop_all_level = 0;
-#define NECP_LOOPBACK_PASS_ALL 1 // Pass all loopback traffic
-#define NECP_LOOPBACK_PASS_WITH_FILTER 2 // Pass all loopback traffic, but activate content filter and/or flow divert if applicable
-
-#if defined(XNU_TARGET_OS_OSX)
-#define NECP_LOOPBACK_PASS_DEFAULT NECP_LOOPBACK_PASS_WITH_FILTER
-#else
-#define NECP_LOOPBACK_PASS_DEFAULT NECP_LOOPBACK_PASS_ALL
-#endif
-
-u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_DEFAULT;
+u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
#define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x10000000
#define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 0x20000000
#define NECP_KERNEL_CONDITION_IS_LOOPBACK 0x40000000
+#define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY 0x80000000
#define NECP_MAX_POLICY_RESULT_SIZE 512
#define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
struct necp_socket_info {
pid_t pid;
+ int32_t pid_version;
uid_t uid;
union necp_sockaddr_union local_addr;
union necp_sockaddr_union remote_addr;
unsigned is_platform_binary : 1;
unsigned used_responsible_pid : 1;
unsigned is_loopback : 1;
- unsigned __pad_bits : 4;
+ unsigned real_is_platform_binary : 1;
+ unsigned is_delegated : 1;
+ unsigned __pad_bits : 6;
};
static lck_grp_attr_t *necp_kernel_policy_grp_attr = NULL;
static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
static void necp_policy_apply_all(struct necp_session *session);
-static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier, u_int16_t cond_packet_filter_tags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
+static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *domain, pid_t cond_pid, int32_t cond_pidversion, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier, u_int16_t cond_packet_filter_tags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
static bool necp_kernel_socket_policies_reprocess(void);
static bool necp_kernel_socket_policies_update_uuid_table(void);
static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
+static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
struct necp_string_id_mapping {
LIST_ENTRY(necp_string_id_mapping) chain;
struct necp_route_rule {
LIST_ENTRY(necp_route_rule) chain;
u_int32_t id;
- u_int32_t default_action;
+ u_int32_t netagent_id;
+ u_int8_t default_action;
u_int8_t cellular_action;
u_int8_t wifi_action;
u_int8_t wired_action;
static u_int32_t necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t *route_rules_array, u_int32_t route_rules_array_size);
static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
static bool necp_route_is_allowed(struct rtentry *route, ifnet_t interface, u_int32_t route_rule_id, u_int32_t *interface_type_denied);
+static uint32_t necp_route_get_netagent(struct rtentry *route, u_int32_t route_rule_id);
static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
static inline void necp_get_parent_cred_result(proc_t proc, struct necp_socket_info *info);
validated = TRUE;
break;
}
+ case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
+ validated = TRUE;
+ break;
+ }
default: {
validated = FALSE;
break;
validated = TRUE;
break;
}
+ case NECP_ROUTE_RULE_USE_NETAGENT: {
+ u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
+ validated = (rule_length >= sizeof(uuid_t));
+ break;
+ }
default: {
validated = FALSE;
break;
num_conditions++;
}
if (condition_mask & NECP_KERNEL_CONDITION_PID) {
- condition_tlv_length += sizeof(pid_t);
+ condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
num_conditions++;
}
if (condition_mask & NECP_KERNEL_CONDITION_UID) {
if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
num_conditions++;
}
+ if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
+ num_conditions++;
+ }
}
condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t)); // These are for the condition TLVs. The space for "value" is already accounted for above.
}
}
if (condition_mask & NECP_KERNEL_CONDITION_PID) {
- cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_PID, sizeof(policy->cond_pid), &policy->cond_pid,
+ uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
+ memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
+ memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
+ cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_PID, sizeof(pid_buffer), &pid_buffer,
cond_buf, condition_tlv_length);
}
if (condition_mask & NECP_KERNEL_CONDITION_UID) {
if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK, 0, "", cond_buf, condition_tlv_length);
}
+ if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
+ cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY, 0, "", cond_buf, condition_tlv_length);
+ }
}
cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
char *cond_custom_entitlement = NULL;
char *cond_signing_identifier = NULL;
pid_t cond_pid = 0;
+ int32_t cond_pid_version = 0;
uid_t cond_uid = 0;
necp_app_id cond_app_id = 0;
necp_app_id cond_real_app_id = 0;
master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
}
memcpy(&cond_pid, condition_value, sizeof(cond_pid));
+ if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
+ memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
+ }
socket_only_conditions = TRUE;
}
break;
socket_only_conditions = TRUE;
break;
}
+ case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
+ master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
+ if (condition_is_negative) {
+ master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
+ }
+ socket_only_conditions = TRUE;
+ break;
+ }
default: {
break;
}
}
if (socket_layer_non_id_conditions) {
- necp_kernel_policy_id policy_id = necp_kernel_socket_policy_add(policy->order, session->session_order, session->proc_pid, master_condition_mask, master_condition_negated_mask, cond_app_id, cond_real_app_id, cond_custom_entitlement, cond_account_id, cond_domain, cond_pid, cond_uid, cond_bound_interface, cond_traffic_class, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, &cond_agent_type, &cond_sdk_version, cond_client_flags, cond_signing_identifier, cond_packet_filter_tags, ultimate_result, ultimate_result_parameter);
+ necp_kernel_policy_id policy_id = necp_kernel_socket_policy_add(policy->order, session->session_order, session->proc_pid, master_condition_mask, master_condition_negated_mask, cond_app_id, cond_real_app_id, cond_custom_entitlement, cond_account_id, cond_domain, cond_pid, cond_pid_version, cond_uid, cond_bound_interface, cond_traffic_class, cond_protocol, &cond_local_start, &cond_local_end, cond_local_prefix, &cond_remote_start, &cond_remote_end, cond_remote_prefix, &cond_agent_type, &cond_sdk_version, cond_client_flags, cond_signing_identifier, cond_packet_filter_tags, ultimate_result, ultimate_result_parameter);
if (policy_id == 0) {
NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
return newid;
}
-#define NECP_KERNEL_VALID_SOCKET_CONDITIONS (NECP_KERNEL_CONDITION_APP_ID | NECP_KERNEL_CONDITION_REAL_APP_ID | NECP_KERNEL_CONDITION_DOMAIN | NECP_KERNEL_CONDITION_ACCOUNT_ID | NECP_KERNEL_CONDITION_PID | NECP_KERNEL_CONDITION_UID | NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_TRAFFIC_CLASS | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_ENTITLEMENT | NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT | NECP_KERNEL_CONDITION_AGENT_TYPE | NECP_KERNEL_CONDITION_HAS_CLIENT | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_CLIENT_FLAGS | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_PLATFORM_BINARY | NECP_KERNEL_CONDITION_SDK_VERSION | NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER | NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS | NECP_KERNEL_CONDITION_IS_LOOPBACK)
+#define NECP_KERNEL_VALID_SOCKET_CONDITIONS (NECP_KERNEL_CONDITION_APP_ID | NECP_KERNEL_CONDITION_REAL_APP_ID | NECP_KERNEL_CONDITION_DOMAIN | NECP_KERNEL_CONDITION_ACCOUNT_ID | NECP_KERNEL_CONDITION_PID | NECP_KERNEL_CONDITION_UID | NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_TRAFFIC_CLASS | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_ENTITLEMENT | NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT | NECP_KERNEL_CONDITION_AGENT_TYPE | NECP_KERNEL_CONDITION_HAS_CLIENT | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_CLIENT_FLAGS | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_PLATFORM_BINARY | NECP_KERNEL_CONDITION_SDK_VERSION | NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER | NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS | NECP_KERNEL_CONDITION_IS_LOOPBACK | NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)
static necp_kernel_policy_id
-necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *cond_domain, pid_t cond_pid, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier, u_int16_t cond_packet_filter_tags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
+necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int32_t condition_mask, u_int32_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *cond_domain, pid_t cond_pid, int32_t cond_pid_version, uid_t cond_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier, u_int16_t cond_packet_filter_tags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
{
struct necp_kernel_socket_policy *new_kernel_policy = NULL;
struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
}
if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
new_kernel_policy->cond_pid = cond_pid;
+ new_kernel_policy->cond_pid_version = cond_pid_version;
}
if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
new_kernel_policy->cond_uid = cond_uid;
}
if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
- compared_policy->cond_pid != policy->cond_pid) {
+ (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
continue;
}
}
static struct necp_route_rule *
-necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list *list, u_int32_t default_action, u_int8_t cellular_action, u_int8_t wifi_action, u_int8_t wired_action, u_int8_t expensive_action, u_int8_t constrained_action, u_int32_t *if_indices, u_int8_t *if_actions)
+necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list *list, u_int8_t default_action, u_int8_t cellular_action, u_int8_t wifi_action, u_int8_t wired_action, u_int8_t expensive_action, u_int8_t constrained_action, u_int32_t *if_indices, u_int8_t *if_actions, uuid_t netagent_uuid)
{
struct necp_route_rule *searchentry = NULL;
struct necp_route_rule *foundentry = NULL;
break;
}
}
- if (!match_failed && count_a == count_b) {
- foundentry = searchentry;
- break;
+
+ if (match_failed || count_a != count_b) {
+ continue;
+ }
+
+ bool has_agent_a = uuid_is_null(netagent_uuid);
+ bool has_agent_b = (searchentry->netagent_id != 0);
+ if (has_agent_a != has_agent_b) {
+ continue;
}
+
+ if (has_agent_a) {
+ struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
+ if (mapping == NULL) {
+ // Bad mapping, doesn't match
+ continue;
+ }
+ if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
+ // UUIDs don't match
+ continue;
+ }
+ }
+
+ // Rules match!
+ foundentry = searchentry;
+ break;
}
}
size_t offset = 0;
u_int32_t route_rule_id = 0;
struct necp_route_rule *existing_rule = NULL;
- u_int32_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
+ u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
memset(&if_actions, 0, sizeof(if_actions));
+ uuid_t netagent_uuid = {};
+
LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
if (route_rules_array == NULL || route_rules_array_size == 0) {
}
// Process rules
- while (offset < route_rules_array_size) {
+ while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
ifnet_t rule_interface = NULL;
char interface_name[IFXNAMSIZ];
u_int32_t length = 0;
u_int8_t *value = necp_buffer_get_tlv_value(route_rules_array, offset, &length);
+ if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
+ // Invalid TLV goes beyond end of the rules array
+ break;
+ }
+
+ // Increment offset for the next time through the loop
+ offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
+
u_int8_t rule_type = necp_policy_condition_get_type_from_buffer(value, length);
u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
continue;
}
+ if (rule_type == NECP_ROUTE_RULE_USE_NETAGENT) {
+ if (rule_length < sizeof(uuid_t)) {
+ // Too short, skip
+ continue;
+ }
+
+ if (!uuid_is_null(netagent_uuid)) {
+ if (uuid_compare(netagent_uuid, rule_value) != 0) {
+ // UUIDs don't match, skip
+ continue;
+ }
+ } else {
+ // Copy out agent UUID
+ memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
+ }
+
+ // Adjust remaining length
+ rule_value += sizeof(netagent_uuid);
+ rule_length -= sizeof(netagent_uuid);
+ }
+
if (rule_length == 0) {
if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
cellular_action = rule_type;
if (rule_flags == 0) {
default_action = rule_type;
}
- offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
continue;
}
if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
- offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
continue;
}
ifnet_release(rule_interface);
}
}
- offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
}
- existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, if_indices, if_actions);
+ existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, if_indices, if_actions, netagent_uuid);
if (existing_rule != NULL) {
route_rule_id = existing_rule->id;
os_ref_retain_locked(&existing_rule->refcount);
if (new_rule != NULL) {
memset(new_rule, 0, sizeof(struct necp_route_rule));
route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
+ if (!uuid_is_null(netagent_uuid)) {
+ new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
+ }
new_rule->default_action = default_action;
new_rule->cellular_action = cellular_action;
new_rule->wifi_action = wifi_action;
if (existing_rule != NULL) {
if (os_ref_release_locked(&existing_rule->refcount) == 0) {
necp_remove_aggregate_route_rule_for_id(existing_rule->id);
+ necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
LIST_REMOVE(existing_rule, chain);
FREE(existing_rule, M_NECP);
}
return FALSE;
}
+static bool
+necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
+{
+ struct necp_uuid_id_mapping *existing_mapping = NULL;
+
+ if (service_id == 0) {
+ return TRUE;
+ }
+
+ LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
+
+ existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
+ if (existing_mapping != NULL) {
+ if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
+ LIST_REMOVE(existing_mapping, chain);
+ FREE(existing_mapping, M_NECP);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
static bool
necp_kernel_socket_policies_update_uuid_table(void)
const uint32_t sdk = proc_sdk(proc);
// Enforce for iOS, linked on or after version 14
- // If the caller set `check_minor_version`, only enforce starting at 14.TBD
+ // If the caller set `check_minor_version`, only enforce starting at 14.5
if (platform != PLATFORM_IOS ||
sdk == 0 ||
(sdk >> 16) < 14 ||
-#if 0
- (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < TBD)) {
-#else
- (check_minor_version)) {
-#endif
+ (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5)) {
return false;
}
#define NECP_KERNEL_ADDRESS_TYPE_CONDITIONS (NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_LOCAL_NETWORKS)
static void
-necp_application_fillout_info_locked(uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account, char *domain, pid_t pid, uid_t uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, union necp_sockaddr_union *local_addr, union necp_sockaddr_union *remote_addr, u_int16_t local_port, u_int16_t remote_port, bool has_client, proc_t proc, proc_t responsible_proc, u_int32_t drop_order, u_int32_t client_flags, struct necp_socket_info *info, bool is_loopback)
+necp_application_fillout_info_locked(uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account, char *domain, pid_t pid, int32_t pid_version, uid_t uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, union necp_sockaddr_union *local_addr, union necp_sockaddr_union *remote_addr, u_int16_t local_port, u_int16_t remote_port, bool has_client, proc_t real_proc, proc_t proc, proc_t responsible_proc, u_int32_t drop_order, u_int32_t client_flags, struct necp_socket_info *info, bool is_loopback, bool is_delegated)
{
memset(info, 0, sizeof(struct necp_socket_info));
info->pid = pid;
+ info->pid_version = pid_version;
info->uid = uid;
info->protocol = protocol;
info->bound_interface_index = bound_interface_index;
info->drop_order = drop_order;
info->client_flags = client_flags;
info->is_loopback = is_loopback;
+ info->is_delegated = is_delegated;
if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
info->is_platform_binary = necp_is_platform_binary(proc) ? true : false;
}
+ if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
+ info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
+ }
+
if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
if (existing_mapping) {
if (local_port != 0) {
info->local_addr.sin6.sin6_port = local_port;
}
- } else if (local_port != 0) {
- info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
- info->local_addr.sin6.sin6_family = AF_INET6;
- info->local_addr.sin6.sin6_port = local_port;
+ } else {
+ if (remote_addr && remote_addr->sa.sa_len > 0) {
+ info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
+ info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
+ } else {
+ info->local_addr.sin6.sin6_family = AF_INET6;
+ info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
+ }
+ if (local_port != 0) {
+ info->local_addr.sin6.sin6_port = local_port;
+ }
}
if (remote_addr && remote_addr->sa.sa_len > 0) {
memcpy(&info->remote_addr, remote_addr, remote_addr->sa.sa_len);
u_int16_t local_port = 0;
u_int16_t remote_port = 0;
necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
+ bool is_delegated = false;
if (override_local_addr) {
memcpy(&local_addr, override_local_addr, sizeof(local_addr));
// Initialize UID, PID, and UUIDs to the current process
uid_t uid = kauth_cred_getuid(proc_ucred(proc));
pid_t pid = proc_pid(proc);
+ int32_t pid_version = proc_pidversion(proc);
uuid_t application_uuid;
uuid_clear(application_uuid);
uuid_t real_application_uuid;
NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, "euuid");
+ is_delegated = true;
uuid_copy(application_uuid, value);
}
break;
NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, "uuid");
+ is_delegated = true;
uuid_copy(real_application_uuid, value);
}
break;
NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, "pid");
+ is_delegated = true;
memcpy(&pid, value, sizeof(pid_t));
}
break;
NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, "uid");
+ is_delegated = true;
memcpy(&uid, value, sizeof(uid_t));
}
break;
proc_t found_proc = proc_find(pid);
if (found_proc != PROC_NULL) {
effective_proc = found_proc;
+ pid_version = proc_pidversion(effective_proc);
release_eproc = true;
}
}
u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
size_t route_rule_id_array_count = 0;
- necp_application_fillout_info_locked(application_uuid, real_application_uuid, responsible_application_uuid, account, domain, pid, uid, protocol, bound_interface_index, traffic_class, &local_addr, &remote_addr, local_port, remote_port, has_client, effective_proc, responsible_proc, drop_order, client_flags, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
+ necp_application_fillout_info_locked(application_uuid, real_application_uuid, responsible_application_uuid, account, domain, pid, pid_version, uid, protocol, bound_interface_index, traffic_class, &local_addr, &remote_addr, local_port, remote_port, has_client, proc, effective_proc, responsible_proc, drop_order, client_flags, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), is_delegated);
matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map, &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, netagent_use_flags, NECP_MAX_NETAGENTS, required_agent_types, num_required_agent_types, info.used_responsible_pid ? responsible_proc : effective_proc, 0, NULL, NULL, &drop_dest_policy_result, &drop_all_bypass, &flow_divert_aggregate_unit);
// Check for loopback exception again after the policy match
if (v6Route->rt_ifp != NULL) {
*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
- if (ifnet_get_nat64prefix(v6Route->rt_ifp, NULL) == 0) {
+ if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
*flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
}
}
// If the route gets denied, stop matching rules
break;
}
+
+ // Check if there is a route rule that adds an agent
+ u_int32_t netagent_id = necp_route_get_netagent(rt, route_rule_id_array[route_rule_index]);
+ if (netagent_id != 0) {
+ struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
+ if (mapping != NULL) {
+ for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
+ if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
+ // Found open slot
+ uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
+ returned_result->netagent_use_flags[netagent_cursor] = 0;
+ break;
+ }
+ }
+ }
+ }
}
if (rt != NULL && rt->rt_ifp != NULL) {
}
static bool
-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, struct necp_client_parameter_netagent_type *required_agent_types, u_int32_t num_required_agent_types, bool has_client, uint32_t client_flags, int is_platform_binary, proc_t proc, u_int16_t pf_tag, struct rtentry *rt, bool is_loopback)
+necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy, necp_app_id app_id, necp_app_id real_app_id, errno_t cred_result, u_int32_t account_id, struct substring domain, u_int8_t domain_dot_count, pid_t pid, int32_t pid_version, uid_t uid, u_int32_t bound_interface_index, u_int32_t traffic_class, u_int16_t protocol, union necp_sockaddr_union *local, union necp_sockaddr_union *remote, struct necp_client_parameter_netagent_type *required_agent_types, u_int32_t num_required_agent_types, bool has_client, uint32_t client_flags, int is_platform_binary, proc_t proc, u_int16_t pf_tag, struct rtentry *rt, bool is_loopback, bool real_is_platform_binary, bool is_delegated)
{
if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
// No match, matches forbidden pid
return FALSE;
}
+ if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
+ return FALSE;
+ }
} else {
if (pid != kernel_policy->cond_pid) {
// No match, does not match required pid
return FALSE;
}
+ if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
+ return FALSE;
+ }
}
}
}
}
+ if (is_delegated && (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
+ if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
+ if (real_is_platform_binary) {
+ return FALSE;
+ }
+ } else {
+ if (!real_is_platform_binary) {
+ return FALSE;
+ }
+ }
+ }
+
return TRUE;
}
}
static void
-necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, u_int32_t drop_order, proc_t *socket_proc, struct necp_socket_info *info, bool is_loopback)
+necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, bool override_is_inbound, u_int32_t drop_order, proc_t *socket_proc, struct necp_socket_info *info, bool is_loopback)
{
struct socket *so = NULL;
proc_t sock_proc = NULL;
info->drop_order = drop_order;
info->is_loopback = is_loopback;
-
- if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
- info->pid = ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
- }
+ info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID) {
info->uid = kauth_cred_getuid(so->so_cred);
if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
}
- if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
+ if (inp->inp_socket->so_flags1 & SOF1_INBOUND || override_is_inbound) {
info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
}
if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
}
}
+ if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
+ info->pid = socket_pid;
+ info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
+ }
+
if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
info->is_platform_binary = necp_is_platform_binary(sock_proc ? sock_proc : curr_proc) ? true : false;
}
+ if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
+ proc_t real_proc = curr_proc;
+ bool release_real_proc = false;
+ if (so->last_pid != proc_pid(real_proc)) {
+ if (so->last_pid == socket_pid && sock_proc != NULL) {
+ real_proc = sock_proc;
+ } else {
+ proc_t last_proc = proc_find(so->last_pid);
+ if (last_proc != NULL) {
+ real_proc = last_proc;
+ release_real_proc = true;
+ }
+ }
+ }
+ if (real_proc != NULL) {
+ info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
+ if (release_real_proc) {
+ proc_rele(real_proc);
+ }
+ }
+ }
+
if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
if (existing_mapping) {
continue;
}
- if (necp_socket_check_policy(policy_search_array[i], info->application_id, info->real_application_id, info->cred_result, info->account_id, domain_substring, domain_dot_count, info->pid, info->uid, info->bound_interface_index, info->traffic_class, info->protocol, &info->local_addr, &info->remote_addr, required_agent_types, num_required_agent_types, info->has_client, info->client_flags, info->is_platform_binary, proc, pf_tag, rt, info->is_loopback)) {
+ if (necp_socket_check_policy(policy_search_array[i], info->application_id, info->real_application_id, info->cred_result, info->account_id, domain_substring, domain_dot_count, info->pid, info->pid_version, info->uid, info->bound_interface_index, info->traffic_class, info->protocol, &info->local_addr, &info->remote_addr, required_agent_types, num_required_agent_types, info->has_client, info->client_flags, info->is_platform_binary, proc, pf_tag, rt, info->is_loopback, info->real_is_platform_binary, info->is_delegated)) {
if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
// Lock
lck_rw_lock_shared(&necp_kernel_policy_lock);
- necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
+ necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, false, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
// Check info
u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
necp_socket_ip_tunnel_tso(inp);
}
- if (send_local_network_denied_event) {
+ if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
+ inp->inp_policyresult.network_denied_notifies++;
necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
NETPOLICY_NETWORKTYPE_LOCAL);
return TRUE;
}
+static uint32_t
+necp_route_get_netagent(struct rtentry *route, u_int32_t route_rule_id)
+{
+ if (route == NULL) {
+ return 0;
+ }
+
+ struct ifnet *ifp = route->rt_ifp;
+ if (ifp == NULL) {
+ return 0;
+ }
+
+ struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
+ if (route_rule == NULL) {
+ return 0;
+ }
+
+ // No netagent, skip
+ if (route_rule->netagent_id == 0) {
+ return 0;
+ }
+
+ if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT) {
+ return route_rule->netagent_id;
+ }
+
+ for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
+ if (route_rule->exception_if_indices[exception_index] == 0) {
+ break;
+ }
+ if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
+ route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT) {
+ return route_rule->netagent_id;
+ }
+ }
+
+ if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT &&
+ ifp->if_type == IFT_CELLULAR) {
+ return route_rule->netagent_id;
+ }
+
+ if (route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT &&
+ ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI) {
+ return route_rule->netagent_id;
+ }
+
+ if (route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT &&
+ (ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE)) {
+ return route_rule->netagent_id;
+ }
+
+ if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT &&
+ ifp->if_eflags & IFEF_EXPENSIVE) {
+ return route_rule->netagent_id;
+ }
+
+ if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT &&
+ ifp->if_xflags & IFXF_CONSTRAINED) {
+ return route_rule->netagent_id;
+ }
+
+ return 0;
+}
+
bool
necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
{
}
static bool
-necp_socket_is_allowed_to_send_recv_internal(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, ifnet_t interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id, u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
+necp_socket_is_allowed_to_send_recv_internal(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, ifnet_t input_interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id, u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
{
- u_int32_t verifyifindex = interface ? interface->if_index : 0;
+ u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
bool allowed_to_receive = TRUE;
struct necp_socket_info info;
u_int32_t flowhash = 0;
} else {
if (inp->inp_policyresult.results.route_rule_id != 0) {
lck_rw_lock_shared(&necp_kernel_policy_lock);
- if (!necp_route_is_allowed(route, interface, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
+ if (!necp_route_is_allowed(route, input_interface, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
route_allowed = FALSE;
}
lck_rw_done(&necp_kernel_policy_lock);
if (!route_allowed ||
inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
- (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && interface &&
+ (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
allowed_to_receive = FALSE;
} else {
// Actually calculate policy result
lck_rw_lock_shared(&necp_kernel_policy_lock);
- necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
+ necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, input_interface != NULL ? true : false, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
flowhash = necp_socket_calc_flowhash_locked(&info);
if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
inp->inp_policyresult.flowhash == flowhash) {
if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
- (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && interface &&
+ (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
(inp->inp_policyresult.results.route_rule_id != 0 &&
- !necp_route_is_allowed(route, interface, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
+ !necp_route_is_allowed(route, input_interface, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
allowed_to_receive = FALSE;
} else {
if (return_policy_id) {
if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
- (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && interface &&
+ (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
((service_action == NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED ||
service_action == NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED) &&
service.identifier != 0 && service.identifier != NECP_NULL_SERVICE_ID) ||
(route_rule_id != 0 &&
- !necp_route_is_allowed(route, interface, route_rule_id, &interface_type_denied)) ||
+ !necp_route_is_allowed(route, input_interface, route_rule_id, &interface_type_denied)) ||
!necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
allowed_to_receive = FALSE;
} else {
lck_rw_done(&necp_kernel_policy_lock);
- if (send_local_network_denied_event) {
+ if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
+ inp->inp_policyresult.network_denied_notifies++;
necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
NETPOLICY_NETWORKTYPE_LOCAL);
}
bool
-necp_socket_is_allowed_to_send_recv_v4(struct inpcb *inp, u_int16_t local_port, u_int16_t remote_port, struct in_addr *local_addr, struct in_addr *remote_addr, ifnet_t interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id, u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
+necp_socket_is_allowed_to_send_recv_v4(struct inpcb *inp, u_int16_t local_port, u_int16_t remote_port, struct in_addr *local_addr, struct in_addr *remote_addr, ifnet_t input_interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id, u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
{
struct sockaddr_in local = {};
struct sockaddr_in remote = {};
memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
- return necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, interface,
+ return necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, input_interface,
pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
}
bool
-necp_socket_is_allowed_to_send_recv_v6(struct inpcb *inp, u_int16_t local_port, u_int16_t remote_port, struct in6_addr *local_addr, struct in6_addr *remote_addr, ifnet_t interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id, u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
+necp_socket_is_allowed_to_send_recv_v6(struct inpcb *inp, u_int16_t local_port, u_int16_t remote_port, struct in6_addr *local_addr, struct in6_addr *remote_addr, ifnet_t input_interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id, u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
{
struct sockaddr_in6 local = {};
struct sockaddr_in6 remote = {};
memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
- return necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, interface,
+ return necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, input_interface,
pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
}
bool
-necp_socket_is_allowed_to_send_recv(struct inpcb *inp, ifnet_t interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id,
+necp_socket_is_allowed_to_send_recv(struct inpcb *inp, ifnet_t input_interface, u_int16_t pf_tag, necp_kernel_policy_id *return_policy_id,
u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
{
- return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, interface, pf_tag,
+ return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
return_policy_id, return_route_rule_id,
return_skip_policy_id, return_pass_flags);
}