* refactor net_ebpf_ext
This commit is contained in:
Shankar Seal 2021-09-13 14:46:43 -07:00 коммит произвёл GitHub
Родитель f661e74d82
Коммит 4d4c5b5cc7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 689 добавлений и 525 удалений

Просмотреть файл

@ -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>