Родитель
f661e74d82
Коммит
4d4c5b5cc7
|
@ -17,149 +17,30 @@ Environment:
|
||||||
Kernel mode
|
Kernel mode
|
||||||
|
|
||||||
--*/
|
--*/
|
||||||
#define INITGUID
|
|
||||||
|
|
||||||
#include "net_ebpf_ext.h"
|
#include "net_ebpf_ext.h"
|
||||||
|
#include "net_ebpf_ext_bind.h"
|
||||||
|
#include "net_ebpf_ext_xdp.h"
|
||||||
|
|
||||||
#pragma warning(push)
|
// Sublayer GUID.
|
||||||
#pragma warning(disable : 4201) // unnamed struct/union
|
|
||||||
#include <fwpsk.h>
|
|
||||||
#pragma warning(pop)
|
|
||||||
|
|
||||||
#include <fwpmk.h>
|
|
||||||
#include <guiddef.h>
|
|
||||||
#include <netiodef.h>
|
|
||||||
#include <ntddk.h>
|
|
||||||
|
|
||||||
#include "ebpf_ext_attach_provider.h"
|
|
||||||
// ebpf_bind_program_data.h and ebpf_xdp_program_data.h are generated
|
|
||||||
// headers. encode_program_info generates them from the structs
|
|
||||||
// in ebpf_nethooks.h. This workaround exists due to the inability
|
|
||||||
// to call RPC serialization services from kernel mode. Once we switch
|
|
||||||
// to a different serializer, we can get rid of this workaround.
|
|
||||||
#include "ebpf_bind_program_data.h"
|
|
||||||
#include "ebpf_nethooks.h"
|
|
||||||
#include "ebpf_platform.h"
|
|
||||||
#include "ebpf_program_types.h"
|
|
||||||
#include "ebpf_windows.h"
|
|
||||||
#include "ebpf_xdp_program_data.h"
|
|
||||||
|
|
||||||
static HANDLE _net_ebpf_ext_l2_injection_handle = NULL;
|
|
||||||
|
|
||||||
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_xdp_hook_provider_registration = NULL;
|
|
||||||
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_bind_hook_provider_registration = NULL;
|
|
||||||
static ebpf_extension_provider_t* _ebpf_xdp_program_info_provider = NULL;
|
|
||||||
static ebpf_extension_provider_t* _ebpf_bind_program_info_provider = NULL;
|
|
||||||
|
|
||||||
#define RTL_COUNT_OF(arr) (sizeof(arr) / sizeof(arr[0]))
|
|
||||||
|
|
||||||
#define NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION 0
|
|
||||||
|
|
||||||
static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = {
|
|
||||||
sizeof(xdp_md_t),
|
|
||||||
EBPF_OFFSET_OF(xdp_md_t, data),
|
|
||||||
EBPF_OFFSET_OF(xdp_md_t, data_end),
|
|
||||||
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
|
|
||||||
static ebpf_program_info_t _ebpf_xdp_program_info = {{"xdp", &_ebpf_xdp_context_descriptor, {0}}, 0, NULL};
|
|
||||||
|
|
||||||
static ebpf_program_data_t _ebpf_xdp_program_data = {&_ebpf_xdp_program_info, NULL};
|
|
||||||
|
|
||||||
static ebpf_extension_data_t _ebpf_xdp_program_info_provider_data = {
|
|
||||||
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_xdp_program_data), &_ebpf_xdp_program_data};
|
|
||||||
|
|
||||||
static ebpf_context_descriptor_t _ebpf_bind_context_descriptor = {
|
|
||||||
sizeof(bind_md_t), EBPF_OFFSET_OF(bind_md_t, app_id_start), EBPF_OFFSET_OF(bind_md_t, app_id_end), -1};
|
|
||||||
static ebpf_program_info_t _ebpf_bind_program_info = {{"bind", &_ebpf_bind_context_descriptor, {0}}, 0, NULL};
|
|
||||||
|
|
||||||
static ebpf_program_data_t _ebpf_bind_program_data = {&_ebpf_bind_program_info, NULL};
|
|
||||||
|
|
||||||
static ebpf_extension_data_t _ebpf_bind_program_info_provider_data = {
|
|
||||||
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_bind_program_data), &_ebpf_bind_program_data};
|
|
||||||
// Callout and sublayer GUIDs
|
|
||||||
|
|
||||||
// 7c7b3fb9-3331-436a-98e1-b901df457fff
|
// 7c7b3fb9-3331-436a-98e1-b901df457fff
|
||||||
DEFINE_GUID(EBPF_HOOK_SUBLAYER, 0x7c7b3fb9, 0x3331, 0x436a, 0x98, 0xe1, 0xb9, 0x01, 0xdf, 0x45, 0x7f, 0xff);
|
DEFINE_GUID(EBPF_HOOK_SUBLAYER, 0x7c7b3fb9, 0x3331, 0x436a, 0x98, 0xe1, 0xb9, 0x01, 0xdf, 0x45, 0x7f, 0xff);
|
||||||
|
|
||||||
// 5a5614e5-6b64-4738-8367-33c6ca07bf8f
|
|
||||||
DEFINE_GUID(EBPF_HOOK_L2_CALLOUT, 0x5a5614e5, 0x6b64, 0x4738, 0x83, 0x67, 0x33, 0xc6, 0xca, 0x07, 0xbf, 0x8f);
|
|
||||||
|
|
||||||
// c69f4de0-3d80-457d-9aea-75faef42ec12
|
|
||||||
DEFINE_GUID(
|
|
||||||
EBPF_HOOK_ALE_BIND_REDIRECT_CALLOUT, 0xc69f4de0, 0x3d80, 0x457d, 0x9a, 0xea, 0x75, 0xfa, 0xef, 0x42, 0xec, 0x12);
|
|
||||||
|
|
||||||
// 732acf94-7319-4fed-97d0-41d3a18f3fa1
|
|
||||||
DEFINE_GUID(
|
|
||||||
EBPF_HOOK_ALE_RESOURCE_ALLOCATION_CALLOUT,
|
|
||||||
0x732acf94,
|
|
||||||
0x7319,
|
|
||||||
0x4fed,
|
|
||||||
0x97,
|
|
||||||
0xd0,
|
|
||||||
0x41,
|
|
||||||
0xd3,
|
|
||||||
0xa1,
|
|
||||||
0x8f,
|
|
||||||
0x3f,
|
|
||||||
0xa1);
|
|
||||||
|
|
||||||
// d5792949-2d91-4023-9993-3f3dd9d54b2b
|
|
||||||
DEFINE_GUID(
|
|
||||||
EBPF_HOOK_ALE_RESOURCE_RELEASE_CALLOUT, 0xd5792949, 0x2d91, 0x4023, 0x99, 0x93, 0x3f, 0x3d, 0xd9, 0xd5, 0x4b, 0x2b);
|
|
||||||
|
|
||||||
// 85e0d8ef-579e-4931-b072-8ee226bb2e9d
|
|
||||||
DEFINE_GUID(EBPF_ATTACH_TYPE_XDP, 0x85e0d8ef, 0x579e, 0x4931, 0xb0, 0x72, 0x8e, 0xe2, 0x26, 0xbb, 0x2e, 0x9d);
|
|
||||||
|
|
||||||
// b9707e04-8127-4c72-833e-05b1fb439496
|
|
||||||
DEFINE_GUID(EBPF_ATTACH_TYPE_BIND, 0xb9707e04, 0x8127, 0x4c72, 0x83, 0x3e, 0x05, 0xb1, 0xfb, 0x43, 0x94, 0x96);
|
|
||||||
|
|
||||||
DEFINE_GUID(EBPF_PROGRAM_TYPE_XDP, 0xf1832a85, 0x85d5, 0x45b0, 0x98, 0xa0, 0x70, 0x69, 0xd6, 0x30, 0x13, 0xb0);
|
|
||||||
|
|
||||||
DEFINE_GUID(EBPF_PROGRAM_TYPE_BIND, 0x608c517c, 0x6c52, 0x4a26, 0xb6, 0x77, 0xbb, 0x1c, 0x34, 0x42, 0x5a, 0xdf);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_net_ebpf_ext_layer_2_classify(
|
_net_ebpf_ext_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uint64_t flow_context);
|
||||||
_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);
|
|
||||||
|
|
||||||
static void
|
|
||||||
_net_ebpf_ext_resource_allocation_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);
|
|
||||||
|
|
||||||
static void
|
|
||||||
_net_ebpf_ext_resource_release_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);
|
|
||||||
|
|
||||||
static void
|
|
||||||
_net_ebpf_ext_no_op_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uint64_t flow_context);
|
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
_net_ebpf_ext_no_op_notify(
|
_net_ebpf_ext_filter_change_notify(
|
||||||
FWPS_CALLOUT_NOTIFY_TYPE callout_notification_type, _In_ const GUID* filter_key, _Inout_ const FWPS_FILTER* filter);
|
FWPS_CALLOUT_NOTIFY_TYPE callout_notification_type, _In_ const GUID* filter_key, _Inout_ const FWPS_FILTER* filter);
|
||||||
|
|
||||||
typedef struct _net_ebpf_ext_wfp_callout_state
|
typedef struct _net_ebpf_ext_wfp_callout_state
|
||||||
{
|
{
|
||||||
const GUID* callout_guid;
|
const GUID* callout_guid;
|
||||||
const GUID* layer_guid;
|
const GUID* layer_guid;
|
||||||
FWPS_CALLOUT_CLASSIFY_FN3 classify_fn;
|
FWPS_CALLOUT_CLASSIFY_FN classify_fn;
|
||||||
FWPS_CALLOUT_NOTIFY_FN3 notify_fn;
|
FWPS_CALLOUT_NOTIFY_FN notify_fn;
|
||||||
FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN0 delete_fn;
|
FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN delete_fn;
|
||||||
wchar_t* name;
|
wchar_t* name;
|
||||||
wchar_t* description;
|
wchar_t* description;
|
||||||
FWP_ACTION_TYPE filter_action_type;
|
FWP_ACTION_TYPE filter_action_type;
|
||||||
|
@ -170,19 +51,19 @@ static net_ebpf_ext_wfp_callout_state_t _net_ebpf_ext_wfp_callout_state[] = {
|
||||||
{
|
{
|
||||||
&EBPF_HOOK_L2_CALLOUT,
|
&EBPF_HOOK_L2_CALLOUT,
|
||||||
&FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE,
|
&FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE,
|
||||||
_net_ebpf_ext_layer_2_classify,
|
net_ebpf_ext_layer_2_classify,
|
||||||
_net_ebpf_ext_no_op_notify,
|
_net_ebpf_ext_filter_change_notify,
|
||||||
_net_ebpf_ext_no_op_flow_delete,
|
_net_ebpf_ext_flow_delete,
|
||||||
L"L2 XDP Callout",
|
L"L2 XDP Callout",
|
||||||
L"L2 callout driver for eBPF at XDP-like layer",
|
L"L2 callout driver for eBPF at XDP-like layer",
|
||||||
FWP_ACTION_CALLOUT_TERMINATING,
|
FWP_ACTION_CALLOUT_TERMINATING,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&EBPF_HOOK_ALE_RESOURCE_ALLOCATION_CALLOUT,
|
&EBPF_HOOK_ALE_RESOURCE_ALLOC_CALLOUT,
|
||||||
&FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4,
|
&FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4,
|
||||||
_net_ebpf_ext_resource_allocation_classify,
|
net_ebpf_ext_resource_allocation_classify,
|
||||||
_net_ebpf_ext_no_op_notify,
|
_net_ebpf_ext_filter_change_notify,
|
||||||
_net_ebpf_ext_no_op_flow_delete,
|
_net_ebpf_ext_flow_delete,
|
||||||
L"Resource Allocation eBPF Callout",
|
L"Resource Allocation eBPF Callout",
|
||||||
L"Resource Allocation callout driver for eBPF",
|
L"Resource Allocation callout driver for eBPF",
|
||||||
FWP_ACTION_CALLOUT_TERMINATING,
|
FWP_ACTION_CALLOUT_TERMINATING,
|
||||||
|
@ -190,9 +71,9 @@ static net_ebpf_ext_wfp_callout_state_t _net_ebpf_ext_wfp_callout_state[] = {
|
||||||
{
|
{
|
||||||
&EBPF_HOOK_ALE_RESOURCE_RELEASE_CALLOUT,
|
&EBPF_HOOK_ALE_RESOURCE_RELEASE_CALLOUT,
|
||||||
&FWPM_LAYER_ALE_RESOURCE_RELEASE_V4,
|
&FWPM_LAYER_ALE_RESOURCE_RELEASE_V4,
|
||||||
_net_ebpf_ext_resource_release_classify,
|
net_ebpf_ext_resource_release_classify,
|
||||||
_net_ebpf_ext_no_op_notify,
|
_net_ebpf_ext_filter_change_notify,
|
||||||
_net_ebpf_ext_no_op_flow_delete,
|
_net_ebpf_ext_flow_delete,
|
||||||
L"Resource Release eBPF Callout",
|
L"Resource Release eBPF Callout",
|
||||||
L"Resource Release callout driver for eBPF",
|
L"Resource Release callout driver for eBPF",
|
||||||
FWP_ACTION_CALLOUT_TERMINATING,
|
FWP_ACTION_CALLOUT_TERMINATING,
|
||||||
|
@ -352,7 +233,7 @@ net_ebpf_ext_register_callouts(_Inout_ void* device_object)
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index = 0; index < RTL_COUNT_OF(_net_ebpf_ext_wfp_callout_state); index++) {
|
for (index = 0; index < EBPF_COUNT_OF(_net_ebpf_ext_wfp_callout_state); index++) {
|
||||||
status = _net_ebpf_ext_register_wfp_callout(&_net_ebpf_ext_wfp_callout_state[index], device_object);
|
status = _net_ebpf_ext_register_wfp_callout(&_net_ebpf_ext_wfp_callout_state[index], device_object);
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
KdPrintEx(
|
KdPrintEx(
|
||||||
|
@ -406,7 +287,7 @@ net_ebpf_ext_unregister_callouts(void)
|
||||||
FwpmEngineClose(_fwp_engine_handle);
|
FwpmEngineClose(_fwp_engine_handle);
|
||||||
_fwp_engine_handle = NULL;
|
_fwp_engine_handle = NULL;
|
||||||
|
|
||||||
for (index = 0; index < RTL_COUNT_OF(_net_ebpf_ext_wfp_callout_state); index++) {
|
for (index = 0; index < EBPF_COUNT_OF(_net_ebpf_ext_wfp_callout_state); index++) {
|
||||||
FwpsCalloutUnregisterById(_net_ebpf_ext_wfp_callout_state[index].assigned_callout_id);
|
FwpsCalloutUnregisterById(_net_ebpf_ext_wfp_callout_state[index].assigned_callout_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -414,249 +295,8 @@ net_ebpf_ext_unregister_callouts(void)
|
||||||
FwpsInjectionHandleDestroy(_net_ebpf_ext_l2_injection_handle);
|
FwpsInjectionHandleDestroy(_net_ebpf_ext_l2_injection_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
_net_ebpf_ext_l2_inject_complete(
|
|
||||||
_In_ const void* context, _Inout_ NET_BUFFER_LIST* packet_clone, BOOLEAN dispatch_level)
|
|
||||||
{
|
|
||||||
UNREFERENCED_PARAMETER(context);
|
|
||||||
FwpsFreeCloneNetBufferList(packet_clone, dispatch_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_net_ebpf_ext_handle_xdp_tx(_Inout_ NET_BUFFER_LIST* packet, _In_ const FWPS_INCOMING_VALUES* incoming_fixed_values)
|
|
||||||
{
|
|
||||||
NET_BUFFER_LIST* packet_clone = NULL;
|
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
|
||||||
|
|
||||||
uint32_t interface_index =
|
|
||||||
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_INTERFACE_INDEX].value.uint32;
|
|
||||||
uint32_t ndis_port =
|
|
||||||
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_NDIS_PORT].value.uint32;
|
|
||||||
|
|
||||||
status = FwpsAllocateCloneNetBufferList(packet, NULL, NULL, 0, &packet_clone);
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
goto Exit;
|
|
||||||
|
|
||||||
status = FwpsInjectMacSendAsync(
|
|
||||||
_net_ebpf_ext_l2_injection_handle,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE,
|
|
||||||
interface_index,
|
|
||||||
ndis_port,
|
|
||||||
packet_clone,
|
|
||||||
_net_ebpf_ext_l2_inject_complete,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
goto Exit;
|
|
||||||
Exit:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_net_ebpf_ext_layer_2_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)
|
|
||||||
/* ++
|
|
||||||
|
|
||||||
A simple classify function at the WFP L2 MAC layer.
|
|
||||||
|
|
||||||
-- */
|
|
||||||
{
|
|
||||||
FWP_ACTION_TYPE action = FWP_ACTION_PERMIT;
|
|
||||||
|
|
||||||
UNREFERENCED_PARAMETER(incoming_metadata_values);
|
|
||||||
UNREFERENCED_PARAMETER(classify_context);
|
|
||||||
UNREFERENCED_PARAMETER(filter);
|
|
||||||
UNREFERENCED_PARAMETER(flow_context);
|
|
||||||
NET_BUFFER_LIST* nbl = (NET_BUFFER_LIST*)layer_data;
|
|
||||||
NET_BUFFER* net_buffer = NULL;
|
|
||||||
uint8_t* packet_buffer;
|
|
||||||
uint32_t result = 0;
|
|
||||||
|
|
||||||
if (!ebpf_ext_attach_enter_rundown(_ebpf_xdp_hook_provider_registration))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (nbl == NULL) {
|
|
||||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Null nbl \n"));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_buffer = NET_BUFFER_LIST_FIRST_NB(nbl);
|
|
||||||
if (net_buffer == NULL) {
|
|
||||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "net_buffer not present\n"));
|
|
||||||
// nothing to do
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
packet_buffer = NdisGetDataBuffer(net_buffer, net_buffer->DataLength, NULL, sizeof(uint16_t), 0);
|
|
||||||
if (!packet_buffer) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
xdp_md_t ctx = {packet_buffer, packet_buffer + net_buffer->DataLength};
|
|
||||||
|
|
||||||
if (ebpf_ext_attach_invoke_hook(_ebpf_xdp_hook_provider_registration, &ctx, &result) == EBPF_SUCCESS) {
|
|
||||||
switch (result) {
|
|
||||||
case XDP_PASS:
|
|
||||||
action = FWP_ACTION_PERMIT;
|
|
||||||
break;
|
|
||||||
case XDP_TX:
|
|
||||||
_net_ebpf_ext_handle_xdp_tx(nbl, incoming_fixed_values);
|
|
||||||
// Fall through.
|
|
||||||
case XDP_DROP:
|
|
||||||
action = FWP_ACTION_BLOCK;
|
|
||||||
classify_output->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
classify_output->actionType = action;
|
|
||||||
|
|
||||||
ebpf_ext_attach_leave_rundown(_ebpf_xdp_hook_provider_registration);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_net_ebpf_ext_resource_truncate_appid(bind_md_t* ctx)
|
|
||||||
{
|
|
||||||
wchar_t* last_separator = (wchar_t*)ctx->app_id_start;
|
|
||||||
for (wchar_t* position = (wchar_t*)ctx->app_id_start; position < (wchar_t*)ctx->app_id_end; position++) {
|
|
||||||
if (*position == '\\') {
|
|
||||||
last_separator = position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (*last_separator == '\\') {
|
|
||||||
last_separator++;
|
|
||||||
}
|
|
||||||
ctx->app_id_start = (uint8_t*)last_separator;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_net_ebpf_ext_resource_allocation_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)
|
|
||||||
/* ++
|
|
||||||
|
|
||||||
A simple classify function at the WFP Resource Allocation layer.
|
|
||||||
|
|
||||||
-- */
|
|
||||||
{
|
|
||||||
SOCKADDR_IN addr = {AF_INET};
|
|
||||||
uint32_t result;
|
|
||||||
bind_md_t ctx;
|
|
||||||
|
|
||||||
UNREFERENCED_PARAMETER(layer_data);
|
|
||||||
UNREFERENCED_PARAMETER(classify_context);
|
|
||||||
UNREFERENCED_PARAMETER(filter);
|
|
||||||
UNREFERENCED_PARAMETER(flow_context);
|
|
||||||
|
|
||||||
if (!ebpf_ext_attach_enter_rundown(_ebpf_bind_hook_provider_registration)) {
|
|
||||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.sin_port =
|
|
||||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value.uint16;
|
|
||||||
addr.sin_addr.S_un.S_addr =
|
|
||||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_ADDRESS].value.uint32;
|
|
||||||
|
|
||||||
ctx.process_id = incoming_metadata_values->processId;
|
|
||||||
memcpy(&ctx.socket_address, &addr, sizeof(addr));
|
|
||||||
ctx.operation = BIND_OPERATION_BIND;
|
|
||||||
ctx.protocol = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL].value.uint8;
|
|
||||||
|
|
||||||
ctx.app_id_start =
|
|
||||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob->data;
|
|
||||||
ctx.app_id_end =
|
|
||||||
ctx.app_id_start +
|
|
||||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob->size;
|
|
||||||
|
|
||||||
_net_ebpf_ext_resource_truncate_appid(&ctx);
|
|
||||||
if (ebpf_ext_attach_invoke_hook(_ebpf_bind_hook_provider_registration, &ctx, &result) == EBPF_SUCCESS) {
|
|
||||||
switch (result) {
|
|
||||||
case BIND_PERMIT:
|
|
||||||
case BIND_REDIRECT:
|
|
||||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
|
||||||
break;
|
|
||||||
case BIND_DENY:
|
|
||||||
classify_output->actionType = FWP_ACTION_BLOCK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Exit:
|
|
||||||
ebpf_ext_attach_leave_rundown(_ebpf_bind_hook_provider_registration);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_net_ebpf_ext_resource_release_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)
|
|
||||||
/* ++
|
|
||||||
|
|
||||||
A simple classify function at the WFP Resource Release layer.
|
|
||||||
|
|
||||||
-- */
|
|
||||||
{
|
|
||||||
SOCKADDR_IN addr = {AF_INET};
|
|
||||||
uint32_t result;
|
|
||||||
bind_md_t ctx;
|
|
||||||
|
|
||||||
UNREFERENCED_PARAMETER(layer_data);
|
|
||||||
UNREFERENCED_PARAMETER(classify_context);
|
|
||||||
UNREFERENCED_PARAMETER(filter);
|
|
||||||
UNREFERENCED_PARAMETER(flow_context);
|
|
||||||
|
|
||||||
if (!ebpf_ext_attach_enter_rundown(_ebpf_bind_hook_provider_registration)) {
|
|
||||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.sin_port = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_PORT].value.uint16;
|
|
||||||
addr.sin_addr.S_un.S_addr =
|
|
||||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_ADDRESS].value.uint32;
|
|
||||||
|
|
||||||
ctx.process_id = incoming_metadata_values->processId;
|
|
||||||
memcpy(&ctx.socket_address, &addr, sizeof(addr));
|
|
||||||
ctx.operation = BIND_OPERATION_UNBIND;
|
|
||||||
ctx.protocol = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_PROTOCOL].value.uint8;
|
|
||||||
|
|
||||||
ctx.app_id_start =
|
|
||||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_ALE_APP_ID].value.byteBlob->data;
|
|
||||||
ctx.app_id_end =
|
|
||||||
ctx.app_id_start +
|
|
||||||
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_ALE_APP_ID].value.byteBlob->size;
|
|
||||||
|
|
||||||
_net_ebpf_ext_resource_truncate_appid(&ctx);
|
|
||||||
|
|
||||||
ebpf_ext_attach_invoke_hook(_ebpf_bind_hook_provider_registration, &ctx, &result);
|
|
||||||
|
|
||||||
classify_output->actionType = FWP_ACTION_PERMIT;
|
|
||||||
|
|
||||||
Exit:
|
|
||||||
ebpf_ext_attach_leave_rundown(_ebpf_bind_hook_provider_registration);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
_net_ebpf_ext_no_op_notify(
|
_net_ebpf_ext_filter_change_notify(
|
||||||
FWPS_CALLOUT_NOTIFY_TYPE callout_notification_type, _In_ const GUID* filter_key, _Inout_ const FWPS_FILTER* filter)
|
FWPS_CALLOUT_NOTIFY_TYPE callout_notification_type, _In_ const GUID* filter_key, _Inout_ const FWPS_FILTER* filter)
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(callout_notification_type);
|
UNREFERENCED_PARAMETER(callout_notification_type);
|
||||||
|
@ -667,7 +307,7 @@ _net_ebpf_ext_no_op_notify(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_net_ebpf_ext_no_op_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uint64_t flow_context)
|
_net_ebpf_ext_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uint64_t flow_context)
|
||||||
/* ++
|
/* ++
|
||||||
|
|
||||||
This is the flowDeleteFn function of the L2 callout.
|
This is the flowDeleteFn function of the L2 callout.
|
||||||
|
@ -683,90 +323,23 @@ _net_ebpf_ext_no_op_flow_delete(uint16_t layer_id, uint32_t fwpm_callout_id, uin
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
net_ebpf_ext_register_providers()
|
net_ebpf_ext_register_providers()
|
||||||
{
|
{
|
||||||
ebpf_result_t return_value;
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
return_value = ebpf_ext_attach_register_provider(
|
|
||||||
&EBPF_PROGRAM_TYPE_XDP,
|
|
||||||
&EBPF_ATTACH_TYPE_XDP,
|
|
||||||
EBPF_EXT_HOOK_EXECUTION_DISPATCH,
|
|
||||||
&_ebpf_xdp_hook_provider_registration);
|
|
||||||
if (return_value != EBPF_SUCCESS) {
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return_value = ebpf_ext_attach_register_provider(
|
status = net_ebpf_ext_xdp_register_providers();
|
||||||
&EBPF_PROGRAM_TYPE_BIND,
|
if (status != STATUS_SUCCESS)
|
||||||
&EBPF_ATTACH_TYPE_BIND,
|
goto Exit;
|
||||||
EBPF_EXT_HOOK_EXECUTION_PASSIVE,
|
|
||||||
&_ebpf_bind_hook_provider_registration);
|
|
||||||
|
|
||||||
if (return_value != EBPF_SUCCESS) {
|
status = net_ebpf_ext_bind_register_providers();
|
||||||
return STATUS_UNSUCCESSFUL;
|
if (status != STATUS_SUCCESS)
|
||||||
}
|
goto Exit;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
Exit:
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
net_ebpf_ext_unregister_providers()
|
net_ebpf_ext_unregister_providers()
|
||||||
{
|
{
|
||||||
ebpf_ext_attach_unregister_provider(_ebpf_xdp_hook_provider_registration);
|
net_ebpf_ext_xdp_unregister_providers();
|
||||||
ebpf_ext_attach_unregister_provider(_ebpf_bind_hook_provider_registration);
|
net_ebpf_ext_bind_unregister_providers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
net_ebpf_ext_program_info_provider_unregister()
|
|
||||||
{
|
|
||||||
ebpf_provider_unload(_ebpf_xdp_program_info_provider);
|
|
||||||
ebpf_provider_unload(_ebpf_bind_program_info_provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
net_ebpf_ext_program_info_provider_register()
|
|
||||||
{
|
|
||||||
ebpf_result_t return_value;
|
|
||||||
ebpf_extension_data_t* provider_data;
|
|
||||||
ebpf_program_data_t* program_data;
|
|
||||||
|
|
||||||
provider_data = &_ebpf_xdp_program_info_provider_data;
|
|
||||||
program_data = (ebpf_program_data_t*)provider_data->data;
|
|
||||||
program_data->program_info->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_XDP;
|
|
||||||
|
|
||||||
return_value = ebpf_provider_load(
|
|
||||||
&_ebpf_xdp_program_info_provider,
|
|
||||||
&EBPF_PROGRAM_TYPE_XDP,
|
|
||||||
NULL,
|
|
||||||
&_ebpf_xdp_program_info_provider_data,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (return_value != EBPF_SUCCESS) {
|
|
||||||
goto Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
provider_data = &_ebpf_bind_program_info_provider_data;
|
|
||||||
program_data = (ebpf_program_data_t*)provider_data->data;
|
|
||||||
program_data->program_info->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_BIND;
|
|
||||||
|
|
||||||
return_value = ebpf_provider_load(
|
|
||||||
&_ebpf_bind_program_info_provider,
|
|
||||||
&EBPF_PROGRAM_TYPE_BIND,
|
|
||||||
NULL,
|
|
||||||
&_ebpf_bind_program_info_provider_data,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (return_value != EBPF_SUCCESS) {
|
|
||||||
goto Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
Done:
|
|
||||||
if (return_value != EBPF_SUCCESS) {
|
|
||||||
net_ebpf_ext_program_info_provider_unregister();
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
} else
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
|
@ -18,8 +18,29 @@ Environment:
|
||||||
|
|
||||||
#include <ntddk.h>
|
#include <ntddk.h>
|
||||||
|
|
||||||
|
#define INITGUID
|
||||||
|
|
||||||
|
#include <fwpmk.h>
|
||||||
|
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4201) // unnamed struct/union
|
||||||
|
#include <fwpsk.h>
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
#include <guiddef.h>
|
||||||
|
#include <netiodef.h>
|
||||||
|
#include <ntddk.h>
|
||||||
|
|
||||||
|
#include "ebpf_ext_attach_provider.h"
|
||||||
|
#include "ebpf_nethooks.h"
|
||||||
|
#include "ebpf_platform.h"
|
||||||
|
#include "ebpf_program_types.h"
|
||||||
|
#include "ebpf_windows.h"
|
||||||
|
|
||||||
|
#define NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION 0
|
||||||
|
|
||||||
//
|
//
|
||||||
// Shared function prototypes
|
// Shared function prototypes.
|
||||||
//
|
//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,7 +61,7 @@ void
|
||||||
net_ebpf_ext_unregister_callouts(void);
|
net_ebpf_ext_unregister_callouts(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register hook providers with eBPF core.
|
* @brief Register network extension NPI providers with eBPF core.
|
||||||
*
|
*
|
||||||
* @retval STATUS_SUCCESS Operation succeeded.
|
* @retval STATUS_SUCCESS Operation succeeded.
|
||||||
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
||||||
|
@ -49,24 +70,8 @@ NTSTATUS
|
||||||
net_ebpf_ext_register_providers();
|
net_ebpf_ext_register_providers();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unregister hook providers from eBPF core.
|
* @brief Unregister network extension NPI providers from eBPF core.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
net_ebpf_ext_unregister_providers();
|
net_ebpf_ext_unregister_providers();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Register program info providers with eBPF core.
|
|
||||||
*
|
|
||||||
* @retval STATUS_SUCCESS Operation succeeded.
|
|
||||||
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
|
||||||
*/
|
|
||||||
NTSTATUS
|
|
||||||
net_ebpf_ext_program_info_provider_register();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Unregister program info providers from eBPF core.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
net_ebpf_ext_program_info_provider_unregister();
|
|
|
@ -0,0 +1,250 @@
|
||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file This file implements the BIND program type hook on eBPF for Windows.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INITGUID
|
||||||
|
|
||||||
|
// ebpf_bind_program_data.h has generated
|
||||||
|
// headers. encode_program_info generates them from the structs
|
||||||
|
// in ebpf_nethooks.h. This workaround exists due to the inability
|
||||||
|
// to call RPC serialization services from kernel mode. Once we switch
|
||||||
|
// to a different serializer, we can get rid of this workaround.
|
||||||
|
#include "ebpf_bind_program_data.h"
|
||||||
|
|
||||||
|
#include "net_ebpf_ext.h"
|
||||||
|
|
||||||
|
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_bind_hook_provider_registration = NULL;
|
||||||
|
static ebpf_extension_provider_t* _ebpf_bind_program_info_provider = NULL;
|
||||||
|
|
||||||
|
static ebpf_context_descriptor_t _ebpf_bind_context_descriptor = {
|
||||||
|
sizeof(bind_md_t), EBPF_OFFSET_OF(bind_md_t, app_id_start), EBPF_OFFSET_OF(bind_md_t, app_id_end), -1};
|
||||||
|
static ebpf_program_info_t _ebpf_bind_program_info = {{"bind", &_ebpf_bind_context_descriptor, {0}}, 0, NULL};
|
||||||
|
|
||||||
|
static ebpf_program_data_t _ebpf_bind_program_data = {&_ebpf_bind_program_info, NULL};
|
||||||
|
|
||||||
|
static ebpf_extension_data_t _ebpf_bind_program_info_provider_data = {
|
||||||
|
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_bind_program_data), &_ebpf_bind_program_data};
|
||||||
|
|
||||||
|
// b9707e04-8127-4c72-833e-05b1fb439496
|
||||||
|
DEFINE_GUID(EBPF_ATTACH_TYPE_BIND, 0xb9707e04, 0x8127, 0x4c72, 0x83, 0x3e, 0x05, 0xb1, 0xfb, 0x43, 0x94, 0x96);
|
||||||
|
|
||||||
|
// 608c517c-6c52-0x4a26-b677-bb01c34425adf
|
||||||
|
DEFINE_GUID(EBPF_PROGRAM_TYPE_BIND, 0x608c517c, 0x6c52, 0x4a26, 0xb6, 0x77, 0xbb, 0x1c, 0x34, 0x42, 0x5a, 0xdf);
|
||||||
|
|
||||||
|
static void
|
||||||
|
_net_ebpf_ext_resource_truncate_appid(bind_md_t* ctx)
|
||||||
|
{
|
||||||
|
wchar_t* last_separator = (wchar_t*)ctx->app_id_start;
|
||||||
|
for (wchar_t* position = (wchar_t*)ctx->app_id_start; position < (wchar_t*)ctx->app_id_end; position++) {
|
||||||
|
if (*position == '\\') {
|
||||||
|
last_separator = position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*last_separator == '\\') {
|
||||||
|
last_separator++;
|
||||||
|
}
|
||||||
|
ctx->app_id_start = (uint8_t*)last_separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
net_ebpf_ext_resource_allocation_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;
|
||||||
|
bind_md_t ctx;
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(layer_data);
|
||||||
|
UNREFERENCED_PARAMETER(classify_context);
|
||||||
|
UNREFERENCED_PARAMETER(filter);
|
||||||
|
UNREFERENCED_PARAMETER(flow_context);
|
||||||
|
|
||||||
|
if (!ebpf_ext_attach_enter_rundown(_ebpf_bind_hook_provider_registration)) {
|
||||||
|
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.sin_port =
|
||||||
|
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value.uint16;
|
||||||
|
addr.sin_addr.S_un.S_addr =
|
||||||
|
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_ADDRESS].value.uint32;
|
||||||
|
|
||||||
|
ctx.process_id = incoming_metadata_values->processId;
|
||||||
|
memcpy(&ctx.socket_address, &addr, sizeof(addr));
|
||||||
|
ctx.operation = BIND_OPERATION_BIND;
|
||||||
|
ctx.protocol = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL].value.uint8;
|
||||||
|
|
||||||
|
ctx.app_id_start =
|
||||||
|
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob->data;
|
||||||
|
ctx.app_id_end =
|
||||||
|
ctx.app_id_start +
|
||||||
|
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_ALE_APP_ID].value.byteBlob->size;
|
||||||
|
|
||||||
|
_net_ebpf_ext_resource_truncate_appid(&ctx);
|
||||||
|
if (ebpf_ext_attach_invoke_hook(_ebpf_bind_hook_provider_registration, &ctx, &result) == EBPF_SUCCESS) {
|
||||||
|
switch (result) {
|
||||||
|
case BIND_PERMIT:
|
||||||
|
case BIND_REDIRECT:
|
||||||
|
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||||
|
break;
|
||||||
|
case BIND_DENY:
|
||||||
|
classify_output->actionType = FWP_ACTION_BLOCK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
ebpf_ext_attach_leave_rundown(_ebpf_bind_hook_provider_registration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
net_ebpf_ext_resource_release_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;
|
||||||
|
bind_md_t ctx;
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(layer_data);
|
||||||
|
UNREFERENCED_PARAMETER(classify_context);
|
||||||
|
UNREFERENCED_PARAMETER(filter);
|
||||||
|
UNREFERENCED_PARAMETER(flow_context);
|
||||||
|
|
||||||
|
if (!ebpf_ext_attach_enter_rundown(_ebpf_bind_hook_provider_registration)) {
|
||||||
|
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.sin_port = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_PORT].value.uint16;
|
||||||
|
addr.sin_addr.S_un.S_addr =
|
||||||
|
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_ADDRESS].value.uint32;
|
||||||
|
|
||||||
|
ctx.process_id = incoming_metadata_values->processId;
|
||||||
|
memcpy(&ctx.socket_address, &addr, sizeof(addr));
|
||||||
|
ctx.operation = BIND_OPERATION_UNBIND;
|
||||||
|
ctx.protocol = incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_PROTOCOL].value.uint8;
|
||||||
|
|
||||||
|
ctx.app_id_start =
|
||||||
|
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_ALE_APP_ID].value.byteBlob->data;
|
||||||
|
ctx.app_id_end =
|
||||||
|
ctx.app_id_start +
|
||||||
|
incoming_fixed_values->incomingValue[FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_ALE_APP_ID].value.byteBlob->size;
|
||||||
|
|
||||||
|
_net_ebpf_ext_resource_truncate_appid(&ctx);
|
||||||
|
|
||||||
|
ebpf_ext_attach_invoke_hook(_ebpf_bind_hook_provider_registration, &ctx, &result);
|
||||||
|
|
||||||
|
classify_output->actionType = FWP_ACTION_PERMIT;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
ebpf_ext_attach_leave_rundown(_ebpf_bind_hook_provider_registration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_net_ebpf_ext_bind_hook_provider_unregister()
|
||||||
|
{
|
||||||
|
ebpf_ext_attach_unregister_provider(_ebpf_bind_hook_provider_registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
_net_ebpf_ext_bind_hook_provider_register()
|
||||||
|
{
|
||||||
|
ebpf_result_t return_value;
|
||||||
|
|
||||||
|
return_value = ebpf_ext_attach_register_provider(
|
||||||
|
&EBPF_PROGRAM_TYPE_BIND,
|
||||||
|
&EBPF_ATTACH_TYPE_BIND,
|
||||||
|
EBPF_EXT_HOOK_EXECUTION_PASSIVE,
|
||||||
|
&_ebpf_bind_hook_provider_registration);
|
||||||
|
|
||||||
|
if (return_value != EBPF_SUCCESS) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
if (return_value != EBPF_SUCCESS) {
|
||||||
|
_net_ebpf_ext_bind_hook_provider_unregister();
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
} else
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_net_ebpf_ext_bind_program_info_provider_unregister()
|
||||||
|
{
|
||||||
|
ebpf_provider_unload(_ebpf_bind_program_info_provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
_net_ebpf_ext_bind_program_info_provider_register()
|
||||||
|
{
|
||||||
|
ebpf_result_t return_value;
|
||||||
|
ebpf_extension_data_t* provider_data;
|
||||||
|
ebpf_program_data_t* program_data;
|
||||||
|
|
||||||
|
provider_data = &_ebpf_bind_program_info_provider_data;
|
||||||
|
program_data = (ebpf_program_data_t*)provider_data->data;
|
||||||
|
program_data->program_info->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_BIND;
|
||||||
|
|
||||||
|
return_value = ebpf_provider_load(
|
||||||
|
&_ebpf_bind_program_info_provider,
|
||||||
|
&EBPF_PROGRAM_TYPE_BIND,
|
||||||
|
NULL,
|
||||||
|
&_ebpf_bind_program_info_provider_data,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (return_value != EBPF_SUCCESS) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
if (return_value != EBPF_SUCCESS) {
|
||||||
|
_net_ebpf_ext_bind_program_info_provider_unregister();
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
} else
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
net_ebpf_ext_bind_register_providers()
|
||||||
|
{
|
||||||
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
status = _net_ebpf_ext_bind_program_info_provider_register();
|
||||||
|
if (status != STATUS_SUCCESS)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
status = _net_ebpf_ext_bind_hook_provider_register();
|
||||||
|
if (status != STATUS_SUCCESS)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
net_ebpf_ext_bind_unregister_providers()
|
||||||
|
{
|
||||||
|
_net_ebpf_ext_bind_hook_provider_unregister();
|
||||||
|
_net_ebpf_ext_bind_program_info_provider_unregister();
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "net_ebpf_ext.h"
|
||||||
|
|
||||||
|
// Callout and sublayer GUIDs
|
||||||
|
|
||||||
|
// 732acf94-7319-4fed-97d0-41d3a18f3fa1
|
||||||
|
DEFINE_GUID(
|
||||||
|
EBPF_HOOK_ALE_RESOURCE_ALLOC_CALLOUT, 0x732acf94, 0x7319, 0x4fed, 0x97, 0xd0, 0x41, 0xd3, 0xa1, 0x8f, 0x3f, 0xa1);
|
||||||
|
|
||||||
|
// d5792949-2d91-4023-9993-3f3dd9d54b2b
|
||||||
|
DEFINE_GUID(
|
||||||
|
EBPF_HOOK_ALE_RESOURCE_RELEASE_CALLOUT, 0xd5792949, 0x2d91, 0x4023, 0x99, 0x93, 0x3f, 0x3d, 0xd9, 0xd5, 0x4b, 0x2b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief WFP classifyFn callback for EBPF_HOOK_ALE_RESOURCE_ALLOC_CALLOUT.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
net_ebpf_ext_resource_allocation_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 WFP classifyFn callback for EBPF_HOOK_ALE_RESOURCE_RELEASE_CALLOUT.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
net_ebpf_ext_resource_release_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 BIND NPI providers.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
net_ebpf_ext_bind_unregister_providers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register BIND NPI providers.
|
||||||
|
*
|
||||||
|
* @retval STATUS_SUCCESS Operation succeeded.
|
||||||
|
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
net_ebpf_ext_bind_register_providers();
|
|
@ -32,7 +32,8 @@ Environment:
|
||||||
#define NET_EBPF_EXT_DEVICE_NAME L"\\Device\\NetEbpfExt"
|
#define NET_EBPF_EXT_DEVICE_NAME L"\\Device\\NetEbpfExt"
|
||||||
|
|
||||||
// Driver global variables
|
// Driver global variables
|
||||||
static DEVICE_OBJECT* _net_ebpf_ext_driver_device_object;
|
static WDFDEVICE _net_ebpf_ext_device = NULL;
|
||||||
|
static DEVICE_OBJECT* _net_ebpf_ext_driver_device_object = NULL;
|
||||||
static BOOLEAN _net_ebpf_ext_driver_unloading_flag = FALSE;
|
static BOOLEAN _net_ebpf_ext_driver_unloading_flag = FALSE;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -40,50 +41,52 @@ static BOOLEAN _net_ebpf_ext_driver_unloading_flag = FALSE;
|
||||||
//
|
//
|
||||||
DRIVER_INITIALIZE DriverEntry;
|
DRIVER_INITIALIZE DriverEntry;
|
||||||
|
|
||||||
static _Function_class_(EVT_WDF_DRIVER_UNLOAD) _IRQL_requires_same_
|
static void
|
||||||
_IRQL_requires_max_(PASSIVE_LEVEL) void __net_ebpf_ext_driver_unload(_In_ WDFDRIVER driver_object)
|
_net_ebpf_ext_driver_uninitialize_objects()
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(driver_object);
|
|
||||||
|
|
||||||
_net_ebpf_ext_driver_unloading_flag = TRUE;
|
_net_ebpf_ext_driver_unloading_flag = TRUE;
|
||||||
|
|
||||||
net_ebpf_ext_program_info_provider_unregister();
|
|
||||||
|
|
||||||
net_ebpf_ext_unregister_providers();
|
net_ebpf_ext_unregister_providers();
|
||||||
|
|
||||||
net_ebpf_ext_unregister_callouts();
|
net_ebpf_ext_unregister_callouts();
|
||||||
|
|
||||||
|
if (_net_ebpf_ext_device != NULL)
|
||||||
|
WdfObjectDelete(_net_ebpf_ext_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Function_class_(EVT_WDF_DRIVER_UNLOAD) _IRQL_requires_same_
|
||||||
|
_IRQL_requires_max_(PASSIVE_LEVEL) void _net_ebpf_ext_driver_unload(_In_ WDFDRIVER driver_object)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(driver_object);
|
||||||
|
_net_ebpf_ext_driver_uninitialize_objects();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create a basic WDF driver, set up the device object
|
// Create and initialize WDF driver, device object,
|
||||||
// for a callout driver and register with NMR.
|
// WFP callouts and NPI providers.
|
||||||
//
|
//
|
||||||
static NTSTATUS
|
static NTSTATUS
|
||||||
__net_ebpf_ext_driver_initialize_objects(
|
_net_ebpf_ext_driver_initialize_objects(_Inout_ DRIVER_OBJECT* driver_object, _In_ const UNICODE_STRING* registry_path)
|
||||||
_Inout_ DRIVER_OBJECT* driver_object,
|
|
||||||
_In_ const UNICODE_STRING* registry_path,
|
|
||||||
_Out_ WDFDRIVER* driver,
|
|
||||||
_Out_ WDFDEVICE* device)
|
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
WDF_DRIVER_CONFIG driver_configuration;
|
WDF_DRIVER_CONFIG driver_configuration;
|
||||||
PWDFDEVICE_INIT device_initialize = NULL;
|
PWDFDEVICE_INIT device_initialize = NULL;
|
||||||
UNICODE_STRING ebpf_device_name;
|
UNICODE_STRING ebpf_device_name;
|
||||||
BOOLEAN device_create_flag = FALSE;
|
WDFDRIVER driver;
|
||||||
|
|
||||||
WDF_DRIVER_CONFIG_INIT(&driver_configuration, WDF_NO_EVENT_CALLBACK);
|
WDF_DRIVER_CONFIG_INIT(&driver_configuration, WDF_NO_EVENT_CALLBACK);
|
||||||
|
|
||||||
driver_configuration.DriverInitFlags |= WdfDriverInitNonPnpDriver;
|
driver_configuration.DriverInitFlags |= WdfDriverInitNonPnpDriver;
|
||||||
driver_configuration.EvtDriverUnload = __net_ebpf_ext_driver_unload;
|
driver_configuration.EvtDriverUnload = _net_ebpf_ext_driver_unload;
|
||||||
|
|
||||||
status = WdfDriverCreate(driver_object, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &driver_configuration, driver);
|
status = WdfDriverCreate(driver_object, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &driver_configuration, &driver);
|
||||||
|
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_initialize = WdfControlDeviceInitAllocate(
|
device_initialize = WdfControlDeviceInitAllocate(
|
||||||
*driver,
|
driver,
|
||||||
&SDDL_DEVOBJ_SYS_ALL_ADM_ALL // only kernel/system and administrators.
|
&SDDL_DEVOBJ_SYS_ALL_ADM_ALL // only kernel/system and administrators.
|
||||||
);
|
);
|
||||||
if (!device_initialize) {
|
if (!device_initialize) {
|
||||||
|
@ -103,7 +106,7 @@ __net_ebpf_ext_driver_initialize_objects(
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = WdfDeviceCreate(&device_initialize, WDF_NO_OBJECT_ATTRIBUTES, device);
|
status = WdfDeviceCreate(&device_initialize, WDF_NO_OBJECT_ATTRIBUTES, &_net_ebpf_ext_device);
|
||||||
|
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
// do not free if any other call
|
// do not free if any other call
|
||||||
|
@ -113,30 +116,19 @@ __net_ebpf_ext_driver_initialize_objects(
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_create_flag = TRUE;
|
_net_ebpf_ext_driver_device_object = WdfDeviceWdmGetDeviceObject(_net_ebpf_ext_device);
|
||||||
|
|
||||||
status = net_ebpf_ext_register_providers();
|
status = net_ebpf_ext_register_providers();
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = net_ebpf_ext_program_info_provider_register();
|
// TODO: https://github.com/microsoft/ebpf-for-windows/issues/521
|
||||||
if (!NT_SUCCESS(status)) {
|
(void)net_ebpf_ext_register_callouts(_net_ebpf_ext_driver_device_object);
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
WdfControlFinishInitializing(*device);
|
WdfControlFinishInitializing(_net_ebpf_ext_device);
|
||||||
|
|
||||||
Exit:
|
Exit:
|
||||||
if (!NT_SUCCESS(status)) {
|
|
||||||
if (device_create_flag && device != NULL) {
|
|
||||||
//
|
|
||||||
// Release the reference on the newly created object, since
|
|
||||||
// we couldn't initialize it.
|
|
||||||
//
|
|
||||||
WdfObjectDelete(*device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,30 +136,22 @@ NTSTATUS
|
||||||
DriverEntry(_In_ DRIVER_OBJECT* driver_object, _In_ UNICODE_STRING* registry_path)
|
DriverEntry(_In_ DRIVER_OBJECT* driver_object, _In_ UNICODE_STRING* registry_path)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
WDFDRIVER driver;
|
|
||||||
WDFDEVICE device;
|
|
||||||
|
|
||||||
// Request NX Non-Paged Pool when available
|
// Request NX Non-Paged Pool when available
|
||||||
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
|
||||||
|
|
||||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "NetEbpfExt: DriverEntry\n"));
|
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "NetEbpfExt: DriverEntry\n"));
|
||||||
|
|
||||||
status = __net_ebpf_ext_driver_initialize_objects(driver_object, registry_path, &driver, &device);
|
status = _net_ebpf_ext_driver_initialize_objects(driver_object, registry_path);
|
||||||
|
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
_net_ebpf_ext_driver_device_object = WdfDeviceWdmGetDeviceObject(device);
|
|
||||||
|
|
||||||
net_ebpf_ext_register_callouts(_net_ebpf_ext_driver_device_object);
|
|
||||||
// ignore status. at boot, registration can fail.
|
|
||||||
// we will try to re-register during program load.
|
|
||||||
|
|
||||||
Exit:
|
Exit:
|
||||||
|
|
||||||
if (!NT_SUCCESS(status)) {
|
if (!NT_SUCCESS(status)) {
|
||||||
net_ebpf_ext_unregister_callouts();
|
_net_ebpf_ext_driver_uninitialize_objects();
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file This file implements the XDP program type hook and helper functions on eBPF for Windows.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INITGUID
|
||||||
|
|
||||||
|
// ebpf_xdp_program_data.h has generated
|
||||||
|
// headers. encode_program_info generates them from the structs
|
||||||
|
// in ebpf_nethooks.h. This workaround exists due to the inability
|
||||||
|
// to call RPC serialization services from kernel mode. Once we switch
|
||||||
|
// to a different serializer, we can get rid of this workaround.
|
||||||
|
#include "ebpf_xdp_program_data.h"
|
||||||
|
|
||||||
|
#include "net_ebpf_ext.h"
|
||||||
|
|
||||||
|
HANDLE _net_ebpf_ext_l2_injection_handle = NULL;
|
||||||
|
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_xdp_hook_provider_registration = NULL;
|
||||||
|
static ebpf_extension_provider_t* _ebpf_xdp_program_info_provider = NULL;
|
||||||
|
|
||||||
|
static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = {
|
||||||
|
sizeof(xdp_md_t),
|
||||||
|
EBPF_OFFSET_OF(xdp_md_t, data),
|
||||||
|
EBPF_OFFSET_OF(xdp_md_t, data_end),
|
||||||
|
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
|
||||||
|
static ebpf_program_info_t _ebpf_xdp_program_info = {{"xdp", &_ebpf_xdp_context_descriptor, {0}}, 0, NULL};
|
||||||
|
|
||||||
|
static ebpf_program_data_t _ebpf_xdp_program_data = {&_ebpf_xdp_program_info, NULL};
|
||||||
|
|
||||||
|
static ebpf_extension_data_t _ebpf_xdp_program_info_provider_data = {
|
||||||
|
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_xdp_program_data), &_ebpf_xdp_program_data};
|
||||||
|
|
||||||
|
// 85e0d8ef-579e-4931-b072-8ee226bb2e9d
|
||||||
|
DEFINE_GUID(EBPF_ATTACH_TYPE_XDP, 0x85e0d8ef, 0x579e, 0x4931, 0xb0, 0x72, 0x8e, 0xe2, 0x26, 0xbb, 0x2e, 0x9d);
|
||||||
|
|
||||||
|
// f1832a85-85d5-45b0-98a0-7069d63013b0
|
||||||
|
DEFINE_GUID(EBPF_PROGRAM_TYPE_XDP, 0xf1832a85, 0x85d5, 0x45b0, 0x98, 0xa0, 0x70, 0x69, 0xd6, 0x30, 0x13, 0xb0);
|
||||||
|
|
||||||
|
static void
|
||||||
|
_net_ebpf_ext_l2_inject_complete(
|
||||||
|
_In_ const void* context, _Inout_ NET_BUFFER_LIST* packet_clone, BOOLEAN dispatch_level)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(context);
|
||||||
|
FwpsFreeCloneNetBufferList(packet_clone, dispatch_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_net_ebpf_ext_handle_xdp_tx(_Inout_ NET_BUFFER_LIST* packet, _In_ const FWPS_INCOMING_VALUES* incoming_fixed_values)
|
||||||
|
{
|
||||||
|
NET_BUFFER_LIST* packet_clone = NULL;
|
||||||
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
uint32_t interface_index =
|
||||||
|
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_INTERFACE_INDEX].value.uint32;
|
||||||
|
uint32_t ndis_port =
|
||||||
|
incoming_fixed_values->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_NDIS_PORT].value.uint32;
|
||||||
|
|
||||||
|
status = FwpsAllocateCloneNetBufferList(packet, NULL, NULL, 0, &packet_clone);
|
||||||
|
if (status != STATUS_SUCCESS)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
status = FwpsInjectMacSendAsync(
|
||||||
|
_net_ebpf_ext_l2_injection_handle,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE,
|
||||||
|
interface_index,
|
||||||
|
ndis_port,
|
||||||
|
packet_clone,
|
||||||
|
_net_ebpf_ext_l2_inject_complete,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (status != STATUS_SUCCESS)
|
||||||
|
goto Exit;
|
||||||
|
Exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
net_ebpf_ext_layer_2_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)
|
||||||
|
{
|
||||||
|
FWP_ACTION_TYPE action = FWP_ACTION_PERMIT;
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(incoming_metadata_values);
|
||||||
|
UNREFERENCED_PARAMETER(classify_context);
|
||||||
|
UNREFERENCED_PARAMETER(filter);
|
||||||
|
UNREFERENCED_PARAMETER(flow_context);
|
||||||
|
NET_BUFFER_LIST* nbl = (NET_BUFFER_LIST*)layer_data;
|
||||||
|
NET_BUFFER* net_buffer = NULL;
|
||||||
|
uint8_t* packet_buffer;
|
||||||
|
uint32_t result = 0;
|
||||||
|
|
||||||
|
if (!ebpf_ext_attach_enter_rundown(_ebpf_xdp_hook_provider_registration))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (nbl == NULL) {
|
||||||
|
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Null NBL \n"));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buffer = NET_BUFFER_LIST_FIRST_NB(nbl);
|
||||||
|
if (net_buffer == NULL) {
|
||||||
|
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "net_buffer not present\n"));
|
||||||
|
// nothing to do
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet_buffer = NdisGetDataBuffer(net_buffer, net_buffer->DataLength, NULL, sizeof(uint16_t), 0);
|
||||||
|
if (!packet_buffer) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
xdp_md_t ctx = {packet_buffer, packet_buffer + net_buffer->DataLength};
|
||||||
|
|
||||||
|
if (ebpf_ext_attach_invoke_hook(_ebpf_xdp_hook_provider_registration, &ctx, &result) == EBPF_SUCCESS) {
|
||||||
|
switch (result) {
|
||||||
|
case XDP_PASS:
|
||||||
|
action = FWP_ACTION_PERMIT;
|
||||||
|
break;
|
||||||
|
case XDP_TX:
|
||||||
|
_net_ebpf_ext_handle_xdp_tx(nbl, incoming_fixed_values);
|
||||||
|
// Fall through.
|
||||||
|
case XDP_DROP:
|
||||||
|
action = FWP_ACTION_BLOCK;
|
||||||
|
classify_output->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
classify_output->actionType = action;
|
||||||
|
|
||||||
|
ebpf_ext_attach_leave_rundown(_ebpf_xdp_hook_provider_registration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_net_ebpf_ext_xdp_hook_provider_unregister()
|
||||||
|
{
|
||||||
|
ebpf_ext_attach_unregister_provider(_ebpf_xdp_hook_provider_registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
_net_ebpf_ext_xdp_hook_provider_register()
|
||||||
|
{
|
||||||
|
ebpf_result_t return_value;
|
||||||
|
return_value = ebpf_ext_attach_register_provider(
|
||||||
|
&EBPF_PROGRAM_TYPE_XDP,
|
||||||
|
&EBPF_ATTACH_TYPE_XDP,
|
||||||
|
EBPF_EXT_HOOK_EXECUTION_DISPATCH,
|
||||||
|
&_ebpf_xdp_hook_provider_registration);
|
||||||
|
|
||||||
|
if (return_value != EBPF_SUCCESS) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
if (return_value != EBPF_SUCCESS) {
|
||||||
|
_net_ebpf_ext_xdp_hook_provider_unregister();
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
} else
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_net_ebpf_ext_xdp_program_info_provider_unregister()
|
||||||
|
{
|
||||||
|
ebpf_provider_unload(_ebpf_xdp_program_info_provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS
|
||||||
|
_net_ebpf_ext_xdp_program_info_provider_register()
|
||||||
|
{
|
||||||
|
ebpf_result_t return_value;
|
||||||
|
ebpf_extension_data_t* provider_data;
|
||||||
|
ebpf_program_data_t* program_data;
|
||||||
|
|
||||||
|
provider_data = &_ebpf_xdp_program_info_provider_data;
|
||||||
|
program_data = (ebpf_program_data_t*)provider_data->data;
|
||||||
|
program_data->program_info->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_XDP;
|
||||||
|
|
||||||
|
return_value = ebpf_provider_load(
|
||||||
|
&_ebpf_xdp_program_info_provider,
|
||||||
|
&EBPF_PROGRAM_TYPE_XDP,
|
||||||
|
NULL,
|
||||||
|
&_ebpf_xdp_program_info_provider_data,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (return_value != EBPF_SUCCESS) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
if (return_value != EBPF_SUCCESS) {
|
||||||
|
_net_ebpf_ext_xdp_program_info_provider_unregister();
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
} else
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
net_ebpf_ext_xdp_register_providers()
|
||||||
|
{
|
||||||
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
status = _net_ebpf_ext_xdp_program_info_provider_register();
|
||||||
|
if (status != STATUS_SUCCESS)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
status = _net_ebpf_ext_xdp_hook_provider_register();
|
||||||
|
if (status != STATUS_SUCCESS)
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
net_ebpf_ext_xdp_unregister_providers()
|
||||||
|
{
|
||||||
|
_net_ebpf_ext_xdp_hook_provider_unregister();
|
||||||
|
_net_ebpf_ext_xdp_program_info_provider_unregister();
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "net_ebpf_ext.h"
|
||||||
|
|
||||||
|
extern HANDLE _net_ebpf_ext_l2_injection_handle;
|
||||||
|
|
||||||
|
// Callout GUIDs
|
||||||
|
|
||||||
|
// 5a5614e5-6b64-4738-8367-33c6ca07bf8f
|
||||||
|
DEFINE_GUID(EBPF_HOOK_L2_CALLOUT, 0x5a5614e5, 0x6b64, 0x4738, 0x83, 0x67, 0x33, 0xc6, 0xca, 0x07, 0xbf, 0x8f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief WFP classifyFn callback for EBPF_HOOK_L2_CALLOUT.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
net_ebpf_ext_layer_2_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 XDP NPI providers.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
net_ebpf_ext_xdp_unregister_providers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register XDP NPI providers.
|
||||||
|
*
|
||||||
|
* @retval STATUS_SUCCESS Operation succeeded.
|
||||||
|
* @retval STATUS_UNSUCCESSFUL Operation failed.
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
net_ebpf_ext_xdp_register_providers();
|
|
@ -124,6 +124,8 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="net_ebpf_ext_drv.c" />
|
<ClCompile Include="net_ebpf_ext_drv.c" />
|
||||||
<ClCompile Include="net_ebpf_ext.c" />
|
<ClCompile Include="net_ebpf_ext.c" />
|
||||||
|
<ClCompile Include="net_ebpf_ext_bind.c" />
|
||||||
|
<ClCompile Include="net_ebpf_ext_xdp.c" />
|
||||||
<ClCompile Include="ebpf_ext_attach_provider.c" />
|
<ClCompile Include="ebpf_ext_attach_provider.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -134,6 +136,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="net_ebpf_ext.h" />
|
<ClInclude Include="net_ebpf_ext.h" />
|
||||||
|
<ClInclude Include="net_ebpf_ext_bind.h" />
|
||||||
|
<ClInclude Include="net_ebpf_ext_xdp.h" />
|
||||||
<ClInclude Include="ebpf_ext_attach_provider.h" />
|
<ClInclude Include="ebpf_ext_attach_provider.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -29,6 +29,12 @@
|
||||||
<ClCompile Include="net_ebpf_ext.c">
|
<ClCompile Include="net_ebpf_ext.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="net_ebpf_ext_bind.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="net_ebpf_ext_xdp.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="ebpf_ext_attach_provider.c">
|
<ClCompile Include="ebpf_ext_attach_provider.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -40,6 +46,12 @@
|
||||||
<ClInclude Include="ebpf_ext_attach_provider.h">
|
<ClInclude Include="ebpf_ext_attach_provider.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="net_ebpf_ext_bind.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="net_ebpf_ext_xdp.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="resource.h">
|
<ClInclude Include="resource.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче