Sock addr hook (#871)
* remove dependabot from the fork.
* Revert "remove dependabot from the fork."
This reverts commit c542c6cd44
.
* Program info and hook NPI providers for sock_addr.
* fix analysis break.
* PR Feedback.
* PR Feedback 2.
This commit is contained in:
Родитель
68a740223c
Коммит
04582d3f50
|
@ -33,7 +33,8 @@ extern "C"
|
|||
|
||||
/** @brief The programs attached to the INETx_CONNECT hook will be invoked for
|
||||
* connect() calls on TCP or UDP sockets or when a UDP socket calls sendto() to
|
||||
* a unique remote address/port tuple. May be scoped to a network compartment.
|
||||
* a unique remote address/port tuple. May be scoped to a network compartment. The programs return 1 to permit a
|
||||
* connection, and 0 to block it.
|
||||
*/
|
||||
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET4_CONNECT = {
|
||||
0xa82e37b1, 0xaee7, 0x11ec, {0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee}};
|
||||
|
@ -43,7 +44,8 @@ extern "C"
|
|||
|
||||
/** @brief The programs attached to the INETx_RECV_ACCEPT hook will get invoked for
|
||||
* TCP accept() calls or for the first unicast UDP packet from a unique remote
|
||||
* address/port tuple. May be scoped to a network compartment.
|
||||
* address/port tuple. May be scoped to a network compartment. The programs return 1 to permit a connection, and
|
||||
* 0 to block it.
|
||||
*/
|
||||
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_CGROUP_INET4_RECV_ACCEPT = {
|
||||
0xa82e37b3, 0xaee7, 0x11ec, {0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee}};
|
||||
|
|
|
@ -19,6 +19,7 @@ Environment:
|
|||
|
||||
#include "net_ebpf_ext.h"
|
||||
#include "net_ebpf_ext_bind.h"
|
||||
#include "net_ebpf_ext_sock_addr.h"
|
||||
#include "net_ebpf_ext_xdp.h"
|
||||
|
||||
// Globals.
|
||||
|
@ -106,6 +107,46 @@ static net_ebpf_ext_wfp_callout_state_t _net_ebpf_ext_wfp_callout_state[] = {
|
|||
L"Resource Release eBPF Callout v6",
|
||||
L"Resource Release callout for eBPF",
|
||||
FWP_ACTION_CALLOUT_TERMINATING,
|
||||
},
|
||||
{
|
||||
&EBPF_HOOK_ALE_AUTH_CONNECT_V4_CALLOUT,
|
||||
&FWPM_LAYER_ALE_AUTH_CONNECT_V4,
|
||||
net_ebpf_ext_authorize_connection_classify,
|
||||
_net_ebpf_ext_filter_change_notify,
|
||||
_net_ebpf_ext_flow_delete,
|
||||
L"ALE Authorize Connect eBPF Callout v4",
|
||||
L"ALE Authorize Connect callout for eBPF",
|
||||
FWP_ACTION_CALLOUT_TERMINATING,
|
||||
},
|
||||
{
|
||||
&EBPF_HOOK_ALE_AUTH_CONNECT_V6_CALLOUT,
|
||||
&FWPM_LAYER_ALE_AUTH_CONNECT_V6,
|
||||
net_ebpf_ext_authorize_connection_classify,
|
||||
_net_ebpf_ext_filter_change_notify,
|
||||
_net_ebpf_ext_flow_delete,
|
||||
L"ALE Authorize Connect eBPF Callout v6",
|
||||
L"ALE Authorize Connect callout for eBPF",
|
||||
FWP_ACTION_CALLOUT_TERMINATING,
|
||||
},
|
||||
{
|
||||
&EBPF_HOOK_ALE_AUTH_RECV_ACCEPT_V4_CALLOUT,
|
||||
&FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4,
|
||||
net_ebpf_ext_authorize_connection_classify,
|
||||
_net_ebpf_ext_filter_change_notify,
|
||||
_net_ebpf_ext_flow_delete,
|
||||
L"ALE Authorize Receive or Accept eBPF Callout v4",
|
||||
L"ALE Authorize Receive or Accept callout for eBPF",
|
||||
FWP_ACTION_CALLOUT_TERMINATING,
|
||||
},
|
||||
{
|
||||
&EBPF_HOOK_ALE_AUTH_RECV_ACCEPT_V6_CALLOUT,
|
||||
&FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
|
||||
net_ebpf_ext_authorize_connection_classify,
|
||||
_net_ebpf_ext_filter_change_notify,
|
||||
_net_ebpf_ext_flow_delete,
|
||||
L"ALE Authorize Receive or Accept eBPF Callout v6",
|
||||
L"ALE Authorize Receive or Accept callout for eBPF",
|
||||
FWP_ACTION_CALLOUT_TERMINATING,
|
||||
}};
|
||||
|
||||
// WFP globals
|
||||
|
@ -456,6 +497,10 @@ net_ebpf_ext_register_providers()
|
|||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
status = net_ebpf_ext_sock_addr_register_providers();
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
Exit:
|
||||
return status;
|
||||
}
|
||||
|
@ -465,4 +510,5 @@ net_ebpf_ext_unregister_providers()
|
|||
{
|
||||
net_ebpf_ext_xdp_unregister_providers();
|
||||
net_ebpf_ext_bind_unregister_providers();
|
||||
net_ebpf_ext_sock_addr_unregister_providers();
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
#include "net_ebpf_ext_bind.h"
|
||||
|
||||
//
|
||||
// WFP bind layer filter related globals.
|
||||
// WFP filter related globals for bind hook.
|
||||
//
|
||||
|
||||
const net_ebpf_extension_wfp_filter_parameters_t _net_ebpf_extension_bind_wfp_filter_parameters[] = {
|
||||
|
@ -65,12 +65,15 @@ static net_ebpf_extension_hook_provider_t* _ebpf_bind_hook_provider_context = NU
|
|||
//
|
||||
|
||||
static ebpf_result_t
|
||||
_net_ebpf_extension_bind_on_client_attach(_In_ const net_ebpf_extension_hook_client_t* attaching_client)
|
||||
_net_ebpf_extension_bind_on_client_attach(
|
||||
_In_ const net_ebpf_extension_hook_client_t* attaching_client,
|
||||
_In_ const net_ebpf_extension_hook_provider_t* provider_context)
|
||||
{
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
|
||||
// Bind hook allows only one client at a time.
|
||||
if (net_ebpf_extension_hook_get_next_attached_client(_ebpf_bind_hook_provider_context, NULL) != NULL) {
|
||||
if (net_ebpf_extension_hook_get_next_attached_client((net_ebpf_extension_hook_provider_t*)provider_context, NULL) !=
|
||||
NULL) {
|
||||
result = EBPF_ACCESS_DENIED;
|
||||
goto Exit;
|
||||
}
|
||||
|
@ -128,6 +131,7 @@ net_ebpf_ext_bind_register_providers()
|
|||
&hook_provider_parameters,
|
||||
_net_ebpf_extension_bind_on_client_attach,
|
||||
_net_ebpf_extension_bind_on_client_detach,
|
||||
NULL,
|
||||
&_ebpf_bind_hook_provider_context);
|
||||
if (status != EBPF_SUCCESS) {
|
||||
goto Exit;
|
||||
|
|
|
@ -60,9 +60,10 @@ typedef struct _net_ebpf_extension_hook_provider
|
|||
net_ebpf_extension_hook_execution_t execution_type; ///< Hook execution type (PASSIVE or DISPATCH).
|
||||
EX_PUSH_LOCK lock; ///< Lock for synchronization.
|
||||
net_ebpf_extension_hook_on_client_attach attach_callback; /*!< Pointer to hook specific callback to be invoked
|
||||
when a client attaches. */
|
||||
when a client attaches. */
|
||||
net_ebpf_extension_hook_on_client_detach detach_callback; /*!< Pointer to hook specific callback to be invoked
|
||||
when a client detaches. */
|
||||
when a client detaches. */
|
||||
const void* custom_data; ///< Opaque pointer to hook specific data associated for this provider.
|
||||
_Guarded_by_(lock)
|
||||
LIST_ENTRY attached_clients_list; ///< Linked list of hook NPI clients that are attached to this provider.
|
||||
} net_ebpf_extension_hook_provider_t;
|
||||
|
@ -219,6 +220,12 @@ net_ebpf_extension_hook_client_get_provider_data(_In_ const net_ebpf_extension_h
|
|||
return hook_client->provider_data;
|
||||
}
|
||||
|
||||
const void*
|
||||
net_ebpf_extension_hook_provider_get_custom_data(_In_ const net_ebpf_extension_hook_provider_t* provider_context)
|
||||
{
|
||||
return provider_context->custom_data;
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
net_ebpf_extension_hook_invoke_program(
|
||||
_In_ const net_ebpf_extension_hook_client_t* client, _In_ void* context, _Out_ uint32_t* result)
|
||||
|
@ -229,6 +236,58 @@ net_ebpf_extension_hook_invoke_program(
|
|||
return invoke_program(client_binding_context, context, result);
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
net_ebpf_extension_hook_check_attach_parameter(
|
||||
size_t attach_parameter_size,
|
||||
_In_reads_(attach_parameter_size) const void* attach_parameter,
|
||||
_In_reads_(attach_parameter_size) const void* wild_card_attach_parameter,
|
||||
_In_ net_ebpf_extension_hook_provider_t* provider_context)
|
||||
{
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
bool using_wild_card_attach_parameter = FALSE;
|
||||
bool lock_held = FALSE;
|
||||
|
||||
if (memcmp(attach_parameter, wild_card_attach_parameter, attach_parameter_size) == 0)
|
||||
using_wild_card_attach_parameter = TRUE;
|
||||
|
||||
ExAcquirePushLockShared(&provider_context->lock);
|
||||
lock_held = TRUE;
|
||||
if (using_wild_card_attach_parameter) {
|
||||
// Client requested wild card attach parameter. This will only be allowed if there are no other clients
|
||||
// attached.
|
||||
if (!IsListEmpty(&provider_context->attached_clients_list)) {
|
||||
result = EBPF_ACCESS_DENIED;
|
||||
goto Exit;
|
||||
}
|
||||
} else {
|
||||
// Ensure there are no other clients with wild card attach parameter or with the same attach parameter as the
|
||||
// requesting client.
|
||||
|
||||
LIST_ENTRY* link = provider_context->attached_clients_list.Flink;
|
||||
while (link != &provider_context->attached_clients_list) {
|
||||
net_ebpf_extension_hook_client_t* next_client =
|
||||
(net_ebpf_extension_hook_client_t*)CONTAINING_RECORD(link, net_ebpf_extension_hook_client_t, link);
|
||||
|
||||
const ebpf_extension_data_t* next_client_data = next_client->client_data;
|
||||
void* next_client_attach_parameter =
|
||||
(next_client_data->data == NULL) ? wild_card_attach_parameter : next_client_data->data;
|
||||
if (((memcmp(wild_card_attach_parameter, next_client_attach_parameter, attach_parameter_size) == 0)) ||
|
||||
(memcmp(attach_parameter, next_client_attach_parameter, attach_parameter_size) == 0)) {
|
||||
result = EBPF_ACCESS_DENIED;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
link = link->Flink;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
if (lock_held)
|
||||
ExReleasePushLockShared(&provider_context->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback invoked when an eBPF hook NPI client (a.k.a eBPF link object) attaches.
|
||||
*
|
||||
|
@ -290,7 +349,7 @@ net_ebpf_extension_hook_provider_attach_client(
|
|||
hook_client->execution_type = local_provider_context->execution_type;
|
||||
|
||||
// Invoke the hook specific callback to process client attach.
|
||||
result = local_provider_context->attach_callback(hook_client);
|
||||
result = local_provider_context->attach_callback(hook_client, local_provider_context);
|
||||
|
||||
if (result == EBPF_SUCCESS) {
|
||||
status = _ebpf_ext_attach_init_rundown(hook_client);
|
||||
|
@ -372,6 +431,7 @@ net_ebpf_extension_hook_provider_register(
|
|||
_In_ const net_ebpf_extension_hook_provider_parameters_t* parameters,
|
||||
_In_ net_ebpf_extension_hook_on_client_attach attach_callback,
|
||||
_In_ net_ebpf_extension_hook_on_client_detach detach_callback,
|
||||
_In_opt_ const void* custom_data,
|
||||
_Outptr_ net_ebpf_extension_hook_provider_t** provider_context)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
@ -400,6 +460,7 @@ net_ebpf_extension_hook_provider_register(
|
|||
local_provider_context->execution_type = parameters->execution_type;
|
||||
local_provider_context->attach_callback = attach_callback;
|
||||
local_provider_context->detach_callback = detach_callback;
|
||||
local_provider_context->custom_data = custom_data;
|
||||
|
||||
status = NmrRegisterProvider(characteristics, local_provider_context, &local_provider_context->nmr_provider_handle);
|
||||
if (!NT_SUCCESS(status))
|
||||
|
|
|
@ -53,7 +53,7 @@ net_ebpf_extension_hook_client_get_client_data(_In_ const net_ebpf_extension_hoo
|
|||
* @brief Set the hook-specific provider data for the attached client.
|
||||
*
|
||||
* @param[in] hook_client Pointer to attached hook NPI client.
|
||||
* @returns hook-specific provider data.
|
||||
* @param[in] data hook-specific provider data.
|
||||
*
|
||||
*/
|
||||
void
|
||||
|
@ -64,7 +64,7 @@ net_ebpf_extension_hook_client_set_provider_data(_In_ net_ebpf_extension_hook_cl
|
|||
*
|
||||
* @param[in] hook_client Pointer to attached hook NPI client.
|
||||
*
|
||||
* @returns Hook-specific provider data.
|
||||
* @returns Pointer to hook-specific provider data for the attached client.
|
||||
*/
|
||||
const void*
|
||||
net_ebpf_extension_hook_client_get_provider_data(_In_ const net_ebpf_extension_hook_client_t* hook_client);
|
||||
|
@ -74,6 +74,17 @@ net_ebpf_extension_hook_client_get_provider_data(_In_ const net_ebpf_extension_h
|
|||
*/
|
||||
typedef struct _net_ebpf_extension_hook_provider net_ebpf_extension_hook_provider_t;
|
||||
|
||||
/**
|
||||
* @brief Get the hook-specific custom data from the provider.
|
||||
*
|
||||
* @param[in] provider_context Pointer to hook NPI provider.
|
||||
*
|
||||
* @returns Pointer to the hook-specific custom data from the provider.
|
||||
*
|
||||
*/
|
||||
const void*
|
||||
net_ebpf_extension_hook_provider_get_custom_data(_In_ const net_ebpf_extension_hook_provider_t* provider_context);
|
||||
|
||||
/**
|
||||
* @brief Unregister the hook NPI provider.
|
||||
*
|
||||
|
@ -87,13 +98,15 @@ net_ebpf_extension_hook_provider_unregister(_Frees_ptr_opt_ net_ebpf_extension_h
|
|||
* is attempting to attach to the hook NPI provider. The hook NPI client is allowed to attach only if the API returns
|
||||
* success.
|
||||
* @param attaching_client Pointer to context of the hook NPI client that is requesting to be attached.
|
||||
* @param provider_context Pointer to the hook NPI provider context to which the client is being attached.
|
||||
*
|
||||
* @retval EBPF_SUCCESS The operation succeeded.
|
||||
* @retval EBPF_ACCESS_DENIED Request to attach client is denied by the provider.
|
||||
* @retval EBPF_INVALID_ARGUMENT One or more parameters are incorrect.
|
||||
*/
|
||||
typedef ebpf_result_t (*net_ebpf_extension_hook_on_client_attach)(
|
||||
_In_ const net_ebpf_extension_hook_client_t* attaching_client);
|
||||
_In_ const net_ebpf_extension_hook_client_t* attaching_client,
|
||||
_In_ const net_ebpf_extension_hook_provider_t* provider_context);
|
||||
|
||||
/**
|
||||
* @brief This callback function should be implemented by hook modules. This callback is invoked when a hook NPI client
|
||||
|
@ -119,6 +132,7 @@ typedef struct _net_ebpf_extension_hook_provider_parameters
|
|||
* @param[in] parameters Pointer to the NPI provider characteristics struct.
|
||||
* @param[in] attach_callback Pointer to callback function to be invoked when a client attaches.
|
||||
* @param[in] detach_callback Pointer to callback function to be invoked when a client detaches.
|
||||
* @param[in] custom_data (Optional) Opaque pointer to hook-specific custom data.
|
||||
* @param[in,out] provider_context Pointer to the provider context being registered.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Operation succeeded.
|
||||
|
@ -129,6 +143,7 @@ net_ebpf_extension_hook_provider_register(
|
|||
_In_ const net_ebpf_extension_hook_provider_parameters_t* parameters,
|
||||
_In_ net_ebpf_extension_hook_on_client_attach attach_callback,
|
||||
_In_ net_ebpf_extension_hook_on_client_detach detach_callback,
|
||||
_In_opt_ const void* custom_data,
|
||||
_Outptr_ net_ebpf_extension_hook_provider_t** provider_context);
|
||||
|
||||
/**
|
||||
|
@ -167,3 +182,21 @@ net_ebpf_extension_hook_client_t*
|
|||
net_ebpf_extension_hook_get_next_attached_client(
|
||||
_In_ net_ebpf_extension_hook_provider_t* provider_context,
|
||||
_In_opt_ const net_ebpf_extension_hook_client_t* client_context);
|
||||
|
||||
/**
|
||||
* @brief Utility function called from net_ebpf_extension_hook_on_client_attach callback of hook providers, that
|
||||
* determines if the attach parameter provided by an attaching client is compatible with the existing clients.
|
||||
* @param[in] attach_parameter_size The expected length (in bytes) of attach parameter for this type of hook.
|
||||
* @param[in] attach_parameter The attach parameter supplied by the client requesting to be attached.
|
||||
* @param[in] wild_card_attach_parameter Pointer to wild card parameter for this type of hook.
|
||||
* @param[in] provider_context Provider module's context.
|
||||
* @retval EBPF_SUCCESS The operation succeeded.
|
||||
* @retval EBPF_ACCESS_DENIED Request to attach client is denied by the provider.
|
||||
* @retval EBPF_INVALID_ARGUMENT One or more parameters are incorrect.
|
||||
*/
|
||||
ebpf_result_t
|
||||
net_ebpf_extension_hook_check_attach_parameter(
|
||||
size_t attach_parameter_size,
|
||||
_In_reads_(attach_parameter_size) const void* attach_parameter,
|
||||
_In_reads_(attach_parameter_size) const void* wild_card_attach_parameter,
|
||||
_In_ net_ebpf_extension_hook_provider_t* provider_context);
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file This file implements the hook for the CGROUP_SOCK_ADDR program type and associated attach types, on eBPF for
|
||||
* Windows.
|
||||
*
|
||||
*/
|
||||
|
||||
#define INITGUID
|
||||
|
||||
#include "net_ebpf_ext_sock_addr.h"
|
||||
|
||||
//
|
||||
// WFP filter related types & globals for SOCK_ADDR hook.
|
||||
//
|
||||
|
||||
const ebpf_attach_type_t* _net_ebpf_extension_sock_addr_attach_types[] = {
|
||||
&EBPF_ATTACH_TYPE_CGROUP_INET4_CONNECT,
|
||||
&EBPF_ATTACH_TYPE_CGROUP_INET4_RECV_ACCEPT,
|
||||
&EBPF_ATTACH_TYPE_CGROUP_INET6_CONNECT,
|
||||
&EBPF_ATTACH_TYPE_CGROUP_INET6_RECV_ACCEPT};
|
||||
|
||||
#define NET_EBPF_SOCK_ADDR_HOOK_PROVIDER_COUNT EBPF_COUNT_OF(_net_ebpf_extension_sock_addr_attach_types)
|
||||
|
||||
const net_ebpf_extension_wfp_filter_parameters_t _net_ebpf_extension_sock_addr_wfp_filter_parameters[] = {
|
||||
{&FWPM_LAYER_ALE_AUTH_CONNECT_V4,
|
||||
&EBPF_HOOK_ALE_AUTH_CONNECT_V4_CALLOUT,
|
||||
L"net eBPF sock_addr hook",
|
||||
L"net eBPF sock_addr hook WFP filter"},
|
||||
{&FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4,
|
||||
&EBPF_HOOK_ALE_AUTH_RECV_ACCEPT_V4_CALLOUT,
|
||||
L"net eBPF sock_addr hook",
|
||||
L"net eBPF sock_addr hook WFP filter"},
|
||||
{&FWPM_LAYER_ALE_AUTH_CONNECT_V6,
|
||||
&EBPF_HOOK_ALE_AUTH_CONNECT_V6_CALLOUT,
|
||||
L"net eBPF sock_addr hook",
|
||||
L"net eBPF sock_addr hook WFP filter"},
|
||||
{&FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
|
||||
&EBPF_HOOK_ALE_AUTH_RECV_ACCEPT_V6_CALLOUT,
|
||||
L"net eBPF sock_addr hook",
|
||||
L"net eBPF sock_addr hook WFP filter"}};
|
||||
|
||||
typedef struct _net_ebpf_extension_sock_addr_wfp_filter_context
|
||||
{
|
||||
const net_ebpf_extension_hook_client_t* client_context;
|
||||
uint32_t compartment_id;
|
||||
uint64_t filter_id;
|
||||
} net_ebpf_extension_sock_addr_wfp_filter_context_t;
|
||||
|
||||
//
|
||||
// SOCK_ADDR Program Information NPI Provider.
|
||||
//
|
||||
|
||||
static ebpf_program_data_t _ebpf_sock_addr_program_data = {&_ebpf_sock_addr_program_info, NULL};
|
||||
|
||||
static ebpf_extension_data_t _ebpf_sock_addr_program_info_provider_data = {
|
||||
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_sock_addr_program_data), &_ebpf_sock_addr_program_data};
|
||||
|
||||
NPI_MODULEID DECLSPEC_SELECTANY _ebpf_sock_addr_program_info_provider_moduleid = {sizeof(NPI_MODULEID), MIT_GUID, {0}};
|
||||
|
||||
static net_ebpf_extension_program_info_provider_t* _ebpf_sock_addr_program_info_provider_context = NULL;
|
||||
|
||||
//
|
||||
// SOCK_ADDR Hook NPI Provider.
|
||||
//
|
||||
|
||||
ebpf_attach_provider_data_t _net_ebpf_sock_addr_hook_provider_data;
|
||||
|
||||
ebpf_extension_data_t _net_ebpf_extension_sock_addr_hook_provider_data = {
|
||||
EBPF_ATTACH_PROVIDER_DATA_VERSION,
|
||||
sizeof(_net_ebpf_sock_addr_hook_provider_data),
|
||||
&_net_ebpf_sock_addr_hook_provider_data};
|
||||
|
||||
NPI_MODULEID DECLSPEC_SELECTANY _ebpf_sock_addr_hook_provider_moduleid[NET_EBPF_SOCK_ADDR_HOOK_PROVIDER_COUNT] = {0};
|
||||
|
||||
static net_ebpf_extension_hook_provider_t*
|
||||
_ebpf_sock_addr_hook_provider_context[NET_EBPF_SOCK_ADDR_HOOK_PROVIDER_COUNT] = {0};
|
||||
|
||||
//
|
||||
// NMR Registration Helper Routines.
|
||||
//
|
||||
|
||||
static ebpf_result_t
|
||||
net_ebpf_extension_sock_addr_on_client_attach(
|
||||
_In_ const net_ebpf_extension_hook_client_t* attaching_client,
|
||||
_In_ const net_ebpf_extension_hook_provider_t* provider_context)
|
||||
{
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
const ebpf_extension_data_t* client_data = net_ebpf_extension_hook_client_get_client_data(attaching_client);
|
||||
uint32_t compartment_id;
|
||||
uint32_t wild_card_compartment_id = UNSPECIFIED_COMPARTMENT_ID;
|
||||
net_ebpf_extension_wfp_filter_parameters_t* filter_parameters = NULL;
|
||||
FWPM_FILTER_CONDITION condition = {0};
|
||||
net_ebpf_extension_sock_addr_wfp_filter_context_t* filter_context = NULL;
|
||||
|
||||
// SOCK_ADDR hook clients must always provide data.
|
||||
if (client_data == NULL) {
|
||||
result = EBPF_INVALID_ARGUMENT;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (client_data->size > 0) {
|
||||
if ((client_data->size != sizeof(uint32_t)) || (client_data->data == NULL)) {
|
||||
result = EBPF_INVALID_ARGUMENT;
|
||||
goto Exit;
|
||||
}
|
||||
compartment_id = *(uint32_t*)client_data->data;
|
||||
} else {
|
||||
// If the client did not specify any attach parameters, we treat that as a wildcard interface index.
|
||||
compartment_id = wild_card_compartment_id;
|
||||
}
|
||||
|
||||
result = net_ebpf_extension_hook_check_attach_parameter(
|
||||
sizeof(compartment_id),
|
||||
&compartment_id,
|
||||
&wild_card_compartment_id,
|
||||
(net_ebpf_extension_hook_provider_t*)provider_context);
|
||||
if (result != EBPF_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
if (client_data->data != NULL)
|
||||
compartment_id = *(uint32_t*)client_data->data;
|
||||
|
||||
// Set compartment id (if not UNSPECIFIED_COMPARTMENT_ID) as WFP filter condition.
|
||||
if (compartment_id != UNSPECIFIED_COMPARTMENT_ID) {
|
||||
condition.fieldKey = FWPM_CONDITION_COMPARTMENT_ID;
|
||||
condition.matchType = FWP_MATCH_EQUAL;
|
||||
condition.conditionValue.type = FWP_UINT32;
|
||||
condition.conditionValue.uint32 = compartment_id;
|
||||
}
|
||||
|
||||
// Allocate buffer for WFP filter context.
|
||||
filter_context = (net_ebpf_extension_sock_addr_wfp_filter_context_t*)ExAllocatePoolUninitialized(
|
||||
NonPagedPoolNx, sizeof(net_ebpf_extension_sock_addr_wfp_filter_context_t), NET_EBPF_EXTENSION_POOL_TAG);
|
||||
if (filter_context == NULL) {
|
||||
result = EBPF_NO_MEMORY;
|
||||
goto Exit;
|
||||
}
|
||||
memset(filter_context, 0, sizeof(net_ebpf_extension_sock_addr_wfp_filter_context_t));
|
||||
filter_context->client_context = attaching_client;
|
||||
filter_context->compartment_id = compartment_id;
|
||||
|
||||
// Get the WFP filter parameters for this hook type.
|
||||
filter_parameters =
|
||||
(net_ebpf_extension_wfp_filter_parameters_t*)net_ebpf_extension_hook_provider_get_custom_data(provider_context);
|
||||
ASSERT(filter_parameters != NULL);
|
||||
|
||||
// Add a single WFP filter at the WFP layer corresponding to the hook type, and set the hook NPI client as the
|
||||
// filter's raw context.
|
||||
result = net_ebpf_extension_add_wfp_filters(
|
||||
1, // filter_count
|
||||
filter_parameters,
|
||||
(compartment_id == UNSPECIFIED_COMPARTMENT_ID) ? 0 : 1,
|
||||
(compartment_id == UNSPECIFIED_COMPARTMENT_ID) ? NULL : &condition,
|
||||
filter_context,
|
||||
&filter_context->filter_id);
|
||||
if (result != EBPF_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
// Set the filter context as the client context's provider data.
|
||||
net_ebpf_extension_hook_client_set_provider_data(
|
||||
(net_ebpf_extension_hook_client_t*)attaching_client, filter_context);
|
||||
|
||||
Exit:
|
||||
if (result != EBPF_SUCCESS) {
|
||||
if (filter_context != NULL)
|
||||
ExFreePool(filter_context);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
_net_ebpf_extension_sock_addr_on_client_detach(_In_ const net_ebpf_extension_hook_client_t* detaching_client)
|
||||
{
|
||||
net_ebpf_extension_sock_addr_wfp_filter_context_t* filter_context =
|
||||
(net_ebpf_extension_sock_addr_wfp_filter_context_t*)net_ebpf_extension_hook_client_get_provider_data(
|
||||
detaching_client);
|
||||
ASSERT(filter_context != NULL);
|
||||
net_ebpf_extension_delete_wfp_filters(1, &filter_context->filter_id);
|
||||
ExFreePool(filter_context);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
net_ebpf_ext_sock_addr_register_providers()
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
const net_ebpf_extension_program_info_provider_parameters_t program_info_provider_parameters = {
|
||||
&_ebpf_sock_addr_program_info_provider_moduleid, &_ebpf_sock_addr_program_info_provider_data};
|
||||
|
||||
_ebpf_sock_addr_program_info.program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_CGROUP_SOCK_ADDR;
|
||||
// Set the program type as the provider module id.
|
||||
_ebpf_sock_addr_program_info_provider_moduleid.Guid = EBPF_PROGRAM_TYPE_CGROUP_SOCK_ADDR;
|
||||
status = net_ebpf_extension_program_info_provider_register(
|
||||
&program_info_provider_parameters, &_ebpf_sock_addr_program_info_provider_context);
|
||||
if (status != STATUS_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
_net_ebpf_sock_addr_hook_provider_data.supported_program_type = EBPF_PROGRAM_TYPE_CGROUP_SOCK_ADDR;
|
||||
for (int i = 0; i < NET_EBPF_SOCK_ADDR_HOOK_PROVIDER_COUNT; i++) {
|
||||
// Set the attach type as the provider module id.
|
||||
const net_ebpf_extension_hook_provider_parameters_t hook_provider_parameters = {
|
||||
&_ebpf_sock_addr_hook_provider_moduleid[i],
|
||||
&_net_ebpf_extension_sock_addr_hook_provider_data,
|
||||
EXECUTION_DISPATCH};
|
||||
|
||||
// Set the attach type as the provider module id.
|
||||
_ebpf_sock_addr_hook_provider_moduleid[i].Length = sizeof(NPI_MODULEID);
|
||||
_ebpf_sock_addr_hook_provider_moduleid[i].Type = MIT_GUID;
|
||||
_ebpf_sock_addr_hook_provider_moduleid[i].Guid = *_net_ebpf_extension_sock_addr_attach_types[i];
|
||||
|
||||
// Register the provider context and pass the pointer to the WFP filter parameters
|
||||
// corresponding to this hook type as custom data.
|
||||
status = net_ebpf_extension_hook_provider_register(
|
||||
&hook_provider_parameters,
|
||||
net_ebpf_extension_sock_addr_on_client_attach,
|
||||
_net_ebpf_extension_sock_addr_on_client_detach,
|
||||
&_net_ebpf_extension_sock_addr_wfp_filter_parameters[i],
|
||||
&_ebpf_sock_addr_hook_provider_context[i]);
|
||||
}
|
||||
|
||||
if (status != EBPF_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
Exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
net_ebpf_ext_sock_addr_unregister_providers()
|
||||
{
|
||||
for (int i = 0; i < NET_EBPF_SOCK_ADDR_HOOK_PROVIDER_COUNT; i++)
|
||||
net_ebpf_extension_hook_provider_unregister(_ebpf_sock_addr_hook_provider_context[i]);
|
||||
net_ebpf_extension_program_info_provider_unregister(_ebpf_sock_addr_program_info_provider_context);
|
||||
}
|
||||
|
||||
//
|
||||
// WFP callout callback functions.
|
||||
//
|
||||
void
|
||||
net_ebpf_ext_authorize_connection_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output)
|
||||
{
|
||||
SOCKADDR_IN addr = {AF_INET};
|
||||
uint32_t result;
|
||||
net_ebpf_extension_hook_client_t* attached_client = NULL;
|
||||
bpf_sock_addr_t sock_addr_ctx = {0};
|
||||
|
||||
UNREFERENCED_PARAMETER(incoming_metadata_values);
|
||||
UNREFERENCED_PARAMETER(layer_data);
|
||||
UNREFERENCED_PARAMETER(classify_context);
|
||||
UNREFERENCED_PARAMETER(flow_context);
|
||||
|
||||
attached_client = (net_ebpf_extension_hook_client_t*)filter->context;
|
||||
ASSERT(attached_client != NULL);
|
||||
if (attached_client == NULL)
|
||||
goto Exit;
|
||||
|
||||
if (!net_ebpf_extension_hook_client_enter_rundown(attached_client, EXECUTION_PASSIVE)) {
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
addr.sin_port = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16;
|
||||
addr.sin_addr.S_un.S_addr =
|
||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32;
|
||||
|
||||
net_ebpf_extension_hook_invoke_program(attached_client, &sock_addr_ctx, &result);
|
||||
|
||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||
|
||||
Exit:
|
||||
if (attached_client)
|
||||
net_ebpf_extension_hook_client_leave_rundown(attached_client, EXECUTION_PASSIVE);
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "net_ebpf_ext.h"
|
||||
|
||||
// Callout and sublayer GUIDs
|
||||
|
||||
// 98849e0b-b07d-11ec-9a30-18602489beee
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_ALE_AUTH_CONNECT_V4_CALLOUT, 0x98849e0b, 0xb07d, 0x11ec, 0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee);
|
||||
|
||||
// 98849e0c-b07d-11ec-9a30-18602489beee
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_ALE_AUTH_RECV_ACCEPT_V4_CALLOUT,
|
||||
0x98849e0c,
|
||||
0xb07d,
|
||||
0x11ec,
|
||||
0x9a,
|
||||
0x30,
|
||||
0x18,
|
||||
0x60,
|
||||
0x24,
|
||||
0x89,
|
||||
0xbe,
|
||||
0xee);
|
||||
|
||||
// 98849e0d-b07d-11ec-9a30-18602489beee
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_ALE_AUTH_CONNECT_V6_CALLOUT, 0x98849e0d, 0xb07d, 0x11ec, 0x9a, 0x30, 0x18, 0x60, 0x24, 0x89, 0xbe, 0xee);
|
||||
|
||||
// 98849e0e-b07d-11ec-9a30-18602489beee
|
||||
DEFINE_GUID(
|
||||
EBPF_HOOK_ALE_AUTH_RECV_ACCEPT_V6_CALLOUT,
|
||||
0x98849e0e,
|
||||
0xb07d,
|
||||
0x11ec,
|
||||
0x9a,
|
||||
0x30,
|
||||
0x18,
|
||||
0x60,
|
||||
0x24,
|
||||
0x89,
|
||||
0xbe,
|
||||
0xee);
|
||||
|
||||
/**
|
||||
* @brief WFP classifyFn callback for EBPF_HOOK_ALE_AUTH_CONNECT_V4/6_CALLOUT &
|
||||
* EBPF_HOOK_ALE_AUTH_RECV_ACCEPT_V4/6_CALLOUT.
|
||||
*
|
||||
*/
|
||||
void
|
||||
net_ebpf_ext_authorize_connection_classify(
|
||||
_In_ const FWPS_INCOMING_VALUES* incoming_fixed_values,
|
||||
_In_ const FWPS_INCOMING_METADATA_VALUES* incoming_metadata_values,
|
||||
_Inout_opt_ void* layer_data,
|
||||
_In_opt_ const void* classify_context,
|
||||
_In_ const FWPS_FILTER* filter,
|
||||
uint64_t flow_context,
|
||||
_Inout_ FWPS_CLASSIFY_OUT* classify_output);
|
||||
|
||||
/**
|
||||
* @brief Unregister CGROUP_SOCK_ADDR NPI providers.
|
||||
*
|
||||
*/
|
||||
void
|
||||
net_ebpf_ext_sock_addr_unregister_providers();
|
||||
|
||||
/**
|
||||
* @brief Register CGROUP_SOCK_ADDR NPI providers.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Operation succeeded.
|
||||
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
||||
*/
|
||||
NTSTATUS
|
||||
net_ebpf_ext_sock_addr_register_providers();
|
|
@ -34,7 +34,7 @@ Exit:
|
|||
}
|
||||
|
||||
//
|
||||
// WFP XDP layer filter related types & globals.
|
||||
// WFP filter related types & globals for XDP hook.
|
||||
//
|
||||
|
||||
const net_ebpf_extension_wfp_filter_parameters_t _net_ebpf_extension_xdp_wfp_filter_parameters[] = {
|
||||
|
@ -95,11 +95,14 @@ static net_ebpf_extension_hook_provider_t* _ebpf_xdp_hook_provider_context = NUL
|
|||
//
|
||||
|
||||
static ebpf_result_t
|
||||
net_ebpf_extension_xdp_on_client_attach(_In_ const net_ebpf_extension_hook_client_t* attaching_client)
|
||||
net_ebpf_extension_xdp_on_client_attach(
|
||||
_In_ const net_ebpf_extension_hook_client_t* attaching_client,
|
||||
_In_ const net_ebpf_extension_hook_provider_t* provider_context)
|
||||
{
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
const ebpf_extension_data_t* client_data = net_ebpf_extension_hook_client_get_client_data(attaching_client);
|
||||
uint32_t if_index;
|
||||
uint32_t wild_card_if_index = 0;
|
||||
uint32_t filter_count;
|
||||
FWPM_FILTER_CONDITION condition = {0};
|
||||
net_ebpf_extension_xdp_wfp_filter_context_t* filter_context = NULL;
|
||||
|
@ -110,49 +113,24 @@ net_ebpf_extension_xdp_on_client_attach(_In_ const net_ebpf_extension_hook_clien
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
// Validate client data.
|
||||
if (client_data->version != EBPF_ATTACH_CLIENT_DATA_VERSION) {
|
||||
result = EBPF_INVALID_ARGUMENT;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (client_data->size > 0) {
|
||||
if ((client_data->size < sizeof(uint32_t)) || (client_data->data == NULL)) {
|
||||
if ((client_data->size != sizeof(uint32_t)) || (client_data->data == NULL)) {
|
||||
result = EBPF_INVALID_ARGUMENT;
|
||||
goto Exit;
|
||||
}
|
||||
if_index = *(uint32_t*)client_data->data;
|
||||
} else {
|
||||
// If the client did not specify any attach parameters, we treat that as a wildcard interface index.
|
||||
if_index = 0;
|
||||
if_index = wild_card_if_index;
|
||||
}
|
||||
|
||||
if (if_index == 0) {
|
||||
// Client requested wildcard interface. This will only be allowed if there are no other clients attached.
|
||||
if (net_ebpf_extension_hook_get_next_attached_client(_ebpf_xdp_hook_provider_context, NULL) != NULL) {
|
||||
result = EBPF_ACCESS_DENIED;
|
||||
goto Exit;
|
||||
}
|
||||
} else {
|
||||
if (!NT_SUCCESS(_net_ebpf_extension_xdp_validate_if_index(if_index))) {
|
||||
result = EBPF_INVALID_ARGUMENT;
|
||||
goto Exit;
|
||||
}
|
||||
// Ensure there are no other clients with interface index 0 or with the same interface index as the
|
||||
// requesting client.
|
||||
net_ebpf_extension_hook_client_t* next_client =
|
||||
net_ebpf_extension_hook_get_next_attached_client(_ebpf_xdp_hook_provider_context, NULL);
|
||||
while (next_client != NULL) {
|
||||
const ebpf_extension_data_t* next_client_data = net_ebpf_extension_hook_client_get_client_data(next_client);
|
||||
uint32_t next_client_if_index = (next_client_data->data == NULL) ? 0 : *(uint32_t*)next_client_data->data;
|
||||
if ((next_client_if_index == 0) || (if_index == next_client_if_index)) {
|
||||
result = EBPF_ACCESS_DENIED;
|
||||
goto Exit;
|
||||
}
|
||||
next_client =
|
||||
net_ebpf_extension_hook_get_next_attached_client(_ebpf_xdp_hook_provider_context, next_client);
|
||||
}
|
||||
}
|
||||
result = net_ebpf_extension_hook_check_attach_parameter(
|
||||
sizeof(if_index), &if_index, &wild_card_if_index, (net_ebpf_extension_hook_provider_t*)provider_context);
|
||||
if (result != EBPF_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
if (client_data->data != NULL)
|
||||
if_index = *(uint32_t*)client_data->data;
|
||||
|
||||
// Set interface index (if non-zero) as WFP filter condition.
|
||||
if (if_index != 0) {
|
||||
|
@ -233,6 +211,7 @@ net_ebpf_ext_xdp_register_providers()
|
|||
&hook_provider_parameters,
|
||||
net_ebpf_extension_xdp_on_client_attach,
|
||||
_net_ebpf_extension_xdp_on_client_detach,
|
||||
NULL,
|
||||
&_ebpf_xdp_hook_provider_context);
|
||||
|
||||
if (status != EBPF_SUCCESS)
|
||||
|
|
|
@ -132,6 +132,7 @@
|
|||
<ClCompile Include="net_ebpf_ext_drv.c" />
|
||||
<ClCompile Include="net_ebpf_ext_hook_provider.c" />
|
||||
<ClCompile Include="net_ebpf_ext_prog_info_provider.c"/>
|
||||
<ClCompile Include="net_ebpf_ext_sock_addr.c" />
|
||||
<ClCompile Include="net_ebpf_ext_xdp.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -143,11 +144,12 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="net_ebpf_ext.h" />
|
||||
<ClInclude Include="net_ebpf_ext_bind.h" />
|
||||
<ClInclude Include="net_ebpf_ext_xdp.h" />
|
||||
<ClInclude Include="net_ebpf_ext_helpers.h" />
|
||||
<ClInclude Include="net_ebpf_ext_hook_provider.h" />
|
||||
<ClInclude Include="net_ebpf_ext_program_info.h" />
|
||||
<ClInclude Include="net_ebpf_ext_prog_info_provider.h"/>
|
||||
<ClInclude Include="net_ebpf_ext_sock_addr.h" />
|
||||
<ClInclude Include="net_ebpf_ext_xdp.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -44,7 +44,7 @@ authorize_v4(bpf_sock_addr_t* ctx)
|
|||
|
||||
verdict = bpf_map_lookup_elem(&connection_policy_map, &tuple_key);
|
||||
|
||||
return (verdict != NULL) ? *verdict : 0;
|
||||
return (verdict != NULL) ? *verdict : 1;
|
||||
}
|
||||
|
||||
__inline int
|
||||
|
@ -60,7 +60,7 @@ authorize_v6(bpf_sock_addr_t* ctx)
|
|||
|
||||
verdict = bpf_map_lookup_elem(&connection_policy_map, &tuple_key);
|
||||
|
||||
return (verdict != NULL) ? *verdict : 0;
|
||||
return (verdict != NULL) ? *verdict : 1;
|
||||
}
|
||||
|
||||
SEC("cgroup/connect4")
|
||||
|
|
Загрузка…
Ссылка в новой задаче