Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 37 additions & 11 deletions ebpf_extensions/neteventebpfext/netevent_ebpf_ext_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
static uint8_t* _event_buffer = NULL; ///< Event buffer for copying the event data.
static size_t _event_buffer_size =
4096; ///< Initial size of the event buffer, which will be dynamically resized as needed.
EX_PUSH_LOCK _ebpf_netevent_push_event_lock;
EX_SPIN_LOCK _ebpf_netevent_push_event_lock;

// Define the GUID for the NetEvent NPI (must match the one of the provider)
const NPIID netevent_npiid = {0x2227e81a, 0x8d8b, 0x11d4, {0xab, 0xad, 0x00, 0x90, 0x27, 0x71, 0x9e, 0x09}};
Expand Down Expand Up @@ -74,15 +74,16 @@ typedef struct netevent_ext_header
typedef struct netevent_ext_function_addresses
{
netevent_ext_header_t header;
netevent_capture_type_t capture_type;
uint32_t helper_function_count;
uint64_t* helper_function_address;
} netevent_ext_function_addresses_t;

// Dispatch table for the client module's helper functions
static const void* _ebpf_netevent_ext_helper_functions[] = {(void*)&_ebpf_netevent_push_event};
const netevent_ext_function_addresses_t _netevent_client_dispatch = {
.header =
{.version = EBPF_HELPER_FUNCTION_ADDRESSES_CURRENT_VERSION, .size = sizeof(netevent_ext_function_addresses_t)},
netevent_ext_function_addresses_t _netevent_client_dispatch = {
.header = {.version = EBPF_NETEVENT_EXTENSION_VERSION, .size = sizeof(netevent_ext_function_addresses_t)},
.capture_type = NetevenCapture_Drop,
.helper_function_count = EBPF_COUNT_OF(_ebpf_netevent_ext_helper_functions),
.helper_function_address = (uint64_t*)_ebpf_netevent_ext_helper_functions};

Expand Down Expand Up @@ -129,12 +130,22 @@ _netevent_ebpf_extension_attach_provider(
_In_ PNPI_REGISTRATION_INSTANCE provider_registration_instance)
{
EBPF_EXT_LOG_ENTRY();
NTSTATUS status;

UNREFERENCED_PARAMETER(client_context);
UNREFERENCED_PARAMETER(provider_registration_instance);

if (provider_registration_instance->NpiSpecificCharacteristics == NULL) {
status = STATUS_NOINTERFACE;
EBPF_EXT_LOG_MESSAGE(
EBPF_EXT_TRACELOG_LEVEL_ERROR,
EBPF_EXT_TRACELOG_KEYWORD_NETEVENT,
"Incompatible netevent provider version");
goto Exit;
}

// Attach to the NetEvent provider module.
NTSTATUS status = NmrClientAttachProvider(
status = NmrClientAttachProvider(
nmr_binding_handle,
&_netevent_client_binding_context,
&_netevent_client_dispatch,
Expand Down Expand Up @@ -211,12 +222,27 @@ _netevent_ebpf_extension_netevent_on_client_attach(
{
ebpf_result_t result = EBPF_SUCCESS;
bool push_lock_acquired = false;
netevent_attach_opts_t* attach_opts;
const ebpf_extension_data_t* client_data = ebpf_extension_hook_client_get_client_data(attaching_client);

EBPF_EXT_LOG_ENTRY();

UNREFERENCED_PARAMETER(attaching_client);
UNREFERENCED_PARAMETER(provider_context);

if (client_data != NULL && client_data->data != NULL) {
attach_opts = (netevent_attach_opts_t*)client_data->data;
if ((attach_opts->capture_type >= NeteventCapture_All) && (attach_opts->capture_type <= NetevenCapture_None)) {
_netevent_client_dispatch.capture_type = attach_opts->capture_type;
} else {
EBPF_EXT_LOG_MESSAGE(
EBPF_EXT_TRACELOG_LEVEL_ERROR,
EBPF_EXT_TRACELOG_KEYWORD_NETEVENT,
"Incorrect capture type in attach opts.");
result = EBPF_OPERATION_NOT_SUPPORTED;
goto Exit;
}
}

ExAcquirePushLockExclusive(&_ebpf_netevent_event_hook_provider_lock);
push_lock_acquired = true;

Expand Down Expand Up @@ -495,13 +521,13 @@ _ebpf_netevent_push_event(_In_ netevent_event_md_t* netevent_event)
ebpf_extension_hook_client_t* client_context = NULL;
netevent_event_notify_context_t netevent_event_notify_context = {0};
uint64_t event_size = netevent_event->event_data_end - netevent_event->event_data_start;
bool push_lock_acquired = false;
bool spin_lock_acquired = false;

// Currently, the verifier does not support read-only contexts, so we need to copy the event data, rather than
// directly passing the existing pointers.
// Verifier feature proposal: https://github.com/vbpf/ebpf-verifier/issues/639
ExAcquirePushLockExclusive(&_ebpf_netevent_push_event_lock);
push_lock_acquired = true;
KIRQL oldIrql = ExAcquireSpinLockExclusive(&_ebpf_netevent_push_event_lock);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like ebpf_extension_hook_get_next_attached_client uses a push lock, which cannot be safely used at DISPATCH_LEVEL. The _ebpf_netevent_push_event callback will execute at IRLQ <= DISPATCH_LEVEL, so the design of the callback needs to take this into account. It seems like this was a missed detail when this callback code was originally written

spin_lock_acquired = true;
if (event_size > _event_buffer_size) {
// If the event buffer is too small, attempt to resize it.
uint8_t* new_event_buffer =
Expand Down Expand Up @@ -550,8 +576,8 @@ _ebpf_netevent_push_event(_In_ netevent_event_md_t* netevent_event)
}

Exit:
if (push_lock_acquired) {
ExReleasePushLockExclusive(&_ebpf_netevent_push_event_lock);
if (spin_lock_acquired) {
ExReleaseSpinLockExclusive(&_ebpf_netevent_push_event_lock, oldIrql);
}

// EBPF_EXT_LOG_EXIT();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "ebpf_ext.h"

#define EBPF_NETEVENT_EXTENSION_POOL_TAG 'tvEN'
#define EBPF_NETEVENT_EXTENSION_VERSION 2

/**
* @brief Register EVENT NPI providers.
Expand Down
16 changes: 16 additions & 0 deletions include/ebpf_netevent_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@ typedef struct _netevent_event_md

} netevent_event_md_t;

//
// Packet capture type
//
typedef enum _netevent_capture_type
{
NeteventCapture_All = 1,
NetevenCapture_Flow,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Neteven" - missing "t"

NetevenCapture_Drop,
NetevenCapture_None
} netevent_capture_type_t;

typedef struct _netevent_attach_opts
{
netevent_capture_type_t capture_type;
} netevent_attach_opts_t;

/*
* @brief Write an event into the ring buffer.
*
Expand Down
9 changes: 9 additions & 0 deletions tests/neteventebpfext/netevent_sim/netevent_npi_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ typedef struct
} netevent_event_info_t;
typedef void (*netevent_push_event)(netevent_event_info_t*);

typedef enum _netevent_capture_type
{
NeteventCapture_All = 1,
NetevenCapture_Flow,
NetevenCapture_Drop,
NetevenCapture_None
} netevent_capture_type_t;

typedef struct netevent_ext_header
{
uint16_t version; ///< Version of the extension data structure.
Expand All @@ -24,6 +32,7 @@ typedef struct netevent_ext_header
typedef struct netevent_ext_function_addresses
{
netevent_ext_header_t header;
netevent_capture_type_t capture_type;
uint32_t helper_function_count;
uint64_t* helper_function_address;
} netevent_ext_function_addresses_t;
21 changes: 21 additions & 0 deletions tests/neteventebpfext/netevent_sim/netevent_npi_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,24 @@ typedef struct PROVIDER_BINDING_CONTEXT_
PNPI_REGISTRATION_INSTANCE client_registration_instance; // Registration instance of the attached client
void* client_binding_context; // Binding context of the attached client
} PROVIDER_BINDING_CONTEXT;

typedef struct _netevent_header
{
USHORT Size;
USHORT Version;

} netevent_header;

typedef struct PROVIDER_NPI_SPECIFIC_CHARACTERISTICS_
{
netevent_header Header;
} PROVIDER_NPI_SPECIFIC_CHARACTERISTICS;

// Define the provider module's NPI specific characteristics=
PROVIDER_NPI_SPECIFIC_CHARACTERISTICS const netevent_npi_specific_characteristics = {
.Header =
{
.Size = sizeof(PROVIDER_NPI_SPECIFIC_CHARACTERISTICS),
.Version = 2,
},
};
20 changes: 12 additions & 8 deletions tests/neteventebpfext/netevent_sim/netevent_sim.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
#include <wdm.h>
#include <wsk.h>
// clang-format on
#include "netevent_types.h"
#include "netevent_npi_client.h"
#include "netevent_npi_provider.h"
#include "netevent_types.h"

#include <guiddef.h>
#include <ntstrsafe.h>
Expand Down Expand Up @@ -63,7 +63,7 @@ const NPI_PROVIDER_CHARACTERISTICS _netevent_provider_characteristics = {
.NpiId = &netevent_npiid,
.ModuleId = &netevent_module_id,
.Number = 0,
.NpiSpecificCharacteristics = NULL}};
.NpiSpecificCharacteristics = &netevent_npi_specific_characteristics}};
PROVIDER_REGISTRATION_CONTEXT _netevent_provider_registration_context = {.provider_registration_handle = NULL};
PROVIDER_BINDING_CONTEXT _netevent_provider_binding_context = {
.client_binding_handle = NULL,
Expand All @@ -86,7 +86,6 @@ timer_dpc_routine(

// Send the payload to the attached NMR client (if any)
if (_netevent_provider_binding_context.client_dispatch != NULL) {

// Acquire the rundown protection
if (!ExAcquireRundownProtection(&_rundown_ref)) {
// The driver is unloading, so return without doing anything
Expand All @@ -95,19 +94,24 @@ timer_dpc_routine(

// Create a test event
LONG counter = InterlockedIncrement(&_event_counter);
netevent_type_drop_t demo_drop_event = {
.header = {.event_type = NOTIFY_EVENT_TYPE_NETEVENT},
netevent_message_t demo_event = {
.header = {.event_type = NOTIFY_EVENT_TYPE_NETEVENT_LOG},
.source_ip = {192, 168, 1, 1},
.destination_ip = {10, 11, 12, 1},
.source_port = 12345,
.destination_port = 80,
.reason = DROP_REASON_SECURITY_POLICY,
.reason = DROP_REASON_NONE,
.event_counter = counter};

if (_netevent_provider_binding_context.client_dispatch->capture_type == NetevenCapture_Drop) {
demo_event.header.event_type = NOTIFY_EVENT_TYPE_NETEVENT_DROP;
demo_event.reason = DROP_REASON_SECURITY_POLICY;
}

// Create the event payload
netevent_event_info_t event_payload = {
.event_data_start = (unsigned char*)&demo_drop_event,
.event_data_end = (unsigned char*)&demo_drop_event + sizeof(demo_drop_event)};
.event_data_start = (unsigned char*)&demo_event,
.event_data_end = (unsigned char*)&demo_event + sizeof(demo_event)};

// Invoke the NPI client's push_event_helper routine
netevent_push_event push_event_helper =
Expand Down
7 changes: 4 additions & 3 deletions tests/neteventebpfext/netevent_sim/netevent_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
//

// The event type we want to process
#define NOTIFY_EVENT_TYPE_NETEVENT 100
#define NOTIFY_EVENT_TYPE_NETEVENT_DROP 100
#define NOTIFY_EVENT_TYPE_NETEVENT_LOG 101

#pragma pack(push, 1) // Set packing to 1 byte boundary

Expand Down Expand Up @@ -37,7 +38,7 @@ typedef enum _drop_reason
DROP_REASON_BANDWIDTH_LIMIT = 3,
DROP_REASON_INACTIVE_TIMEOUT = 4,
} drop_reason;
typedef struct _netevent_type_drop
typedef struct _netevent_message
{
event_header_t header;

Expand All @@ -49,6 +50,6 @@ typedef struct _netevent_type_drop

// Event counter, for testing purposes
unsigned long event_counter;
} netevent_type_drop_t;
} netevent_message_t;

#pragma pack(pop) // Restore default packing
Loading
Loading