Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: Alan Jowett <[email protected]>
  • Loading branch information
Alan-Jowett committed Feb 28, 2024
1 parent 1aa11e8 commit bdd71d2
Show file tree
Hide file tree
Showing 13 changed files with 374 additions and 1 deletion.
14 changes: 14 additions & 0 deletions include/ebpf_nethooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,20 @@ typedef struct _bpf_sock_ops
typedef int
sock_ops_hook_t(bpf_sock_ops_t* context);

typedef enum _process_operation
{
PROCESS_OPERATION_CREATE, ///< Process creation.
PROCESS_OPERATION_DELETE, ///< Process deletion.
} process_operation_t;

typedef struct _process_md
{
uint8_t* process_id_start; ///< Pointer to start of App ID.
uint8_t* process_id_end; ///< Pointer to end of App ID.
uint64_t process_id; ///< Process ID.
process_operation_t operation; ///< Operation to do.
} process_md_t;

#ifdef _MSC_VER
#pragma warning(pop)
#endif
22 changes: 22 additions & 0 deletions include/ebpf_program_attach_type_guids.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ extern "C"
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_XDP_TEST = {
0x0dccc15d, 0xa5f9, 0x4dc1, {0xac, 0x79, 0xfa, 0x25, 0xee, 0xf2, 0x15, 0xc3}};

/** @brief Attach type for handling process creation and destruction events.
*
* Program type: \ref EBPF_ATTACH_TYPE_PROCESS
*/
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_PROCESS = {
0x66e20687, 0x9805, 0x4458, {0xa0, 0xdb, 0x38, 0xe2, 0x20, 0xd3, 0x16, 0x85}};

//
// Program Types.
//
Expand Down Expand Up @@ -177,6 +184,21 @@ extern "C"
*/
__declspec(selectany) ebpf_program_type_t EBPF_PROGRAM_TYPE_XDP_TEST = EBPF_PROGRAM_TYPE_XDP_TEST_GUID;

#define EBPF_PROGRAM_TYPE_PROCESS_GUID \
{ \
0x22ea7b37, 0x1043, 0x4d0d, { 0xb6, 0x0d, 0xca, 0xfa, 0x1c, 0x7b, 0x63, 0x8e } \
}

/** @brief Program type for handling process creation and destruction events.
*
* eBPF program prototype: \ref process_md_t
*
* Attach type(s): \ref EBPF_ATTACH_TYPE_PRCOESS
*
* Helpers available: see bpf_helpers.h
*/
__declspec(selectany) ebpf_program_type_t EBPF_PROGRAM_TYPE_PROCESS = EBPF_PROGRAM_TYPE_PROCESS_GUID;

#ifdef __cplusplus
}
#endif
17 changes: 17 additions & 0 deletions include/ebpf_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,17 @@ enum bpf_prog_type
*/
BPF_PROG_TYPE_SOCK_OPS,

/** @brief Program type for handling process creation and destruction events.
*
* **eBPF program prototype:** \ref process_md_t
*
* **Attach type(s):**
* \ref BPF_ATTACH_TYPE_PROCESS
*
* **Helpers available:** all helpers defined in bpf_helpers.h
*/
BPF_PROG_TYPE_PROCESS,

/** @brief Program type for handling incoming packets as early as possible.
*
* **eBPF program prototype:** \ref xdp_hook_t
Expand Down Expand Up @@ -320,6 +331,12 @@ enum bpf_attach_type
*/
BPF_XDP_TEST,

/** @brief Attach type for handling process events.
*
* **Program type:** \ref BPF_PROG_TYPE_PROCESS
*/
BPF_ATTACH_TYPE_PROCESS,

__MAX_BPF_ATTACH_TYPE,
};

Expand Down
17 changes: 17 additions & 0 deletions netebpfext/net_ebpf_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "net_ebpf_ext.h"
#include "net_ebpf_ext_bind.h"
#include "net_ebpf_ext_process.h"
#include "net_ebpf_ext_sock_addr.h"
#include "net_ebpf_ext_sock_ops.h"
#include "net_ebpf_ext_xdp.h"
Expand All @@ -34,6 +35,7 @@ static bool _net_ebpf_xdp_providers_registered = false;
static bool _net_ebpf_bind_providers_registered = false;
static bool _net_ebpf_sock_addr_providers_registered = false;
static bool _net_ebpf_sock_ops_providers_registered = false;
static bool _net_ebpf_process_providers_registered = false;

static net_ebpf_ext_sublayer_info_t _net_ebpf_ext_sublayers[] = {
{&EBPF_DEFAULT_SUBLAYER, L"EBPF Sub-Layer", L"Sub-Layer for use by eBPF callouts", 0, SUBLAYER_WEIGHT_MAXIMUM},
Expand Down Expand Up @@ -811,6 +813,17 @@ net_ebpf_ext_register_providers()
}
_net_ebpf_sock_ops_providers_registered = true;

status = net_ebpf_ext_process_register_providers();
if (!NT_SUCCESS(status)) {
NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS(
NET_EBPF_EXT_TRACELOG_LEVEL_ERROR,
NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION,
"net_ebpf_ext_process_register_providers failed.",
status);
goto Exit;
}
_net_ebpf_process_providers_registered = true;

Exit:
if (!NT_SUCCESS(status)) {
net_ebpf_ext_unregister_providers();
Expand All @@ -837,4 +850,8 @@ net_ebpf_ext_unregister_providers()
net_ebpf_ext_sock_ops_unregister_providers();
_net_ebpf_sock_ops_providers_registered = false;
}
if (_net_ebpf_process_providers_registered) {
net_ebpf_ext_process_unregister_providers();
_net_ebpf_process_providers_registered = false;
}
}
252 changes: 252 additions & 0 deletions netebpfext/net_ebpf_ext_process.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT

/**
* @file
* @brief This file implements the process program type hook on eBPF for Windows.
*/

#include "ebpf_shared_framework.h"
#include "net_ebpf_ext_process.h"

static ebpf_result_t
_ebpf_process_context_create(
_In_reads_bytes_opt_(data_size_in) const uint8_t* data_in,
size_t data_size_in,
_In_reads_bytes_opt_(context_size_in) const uint8_t* context_in,
size_t context_size_in,
_Outptr_ void** context);

static void
_ebpf_process_context_destroy(
_In_opt_ void* context,
_Out_writes_bytes_to_(*data_size_out, *data_size_out) uint8_t* data_out,
_Inout_ size_t* data_size_out,
_Out_writes_bytes_to_(*context_size_out, *context_size_out) uint8_t* context_out,
_Inout_ size_t* context_size_out);

//
// Process Program Information NPI Provider.
//
static ebpf_program_data_t _ebpf_process_program_data = {
.program_info = &_ebpf_process_program_info,
.context_create = _ebpf_process_context_create,
.context_destroy = _ebpf_process_context_destroy,
.required_irql = PASSIVE_LEVEL,
};

static ebpf_extension_data_t _ebpf_process_program_info_provider_data = {
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_process_program_data), &_ebpf_process_program_data};

NPI_MODULEID DECLSPEC_SELECTANY _ebpf_process_program_info_provider_moduleid = {sizeof(NPI_MODULEID), MIT_GUID, {0}};

static net_ebpf_extension_program_info_provider_t* _ebpf_process_program_info_provider_context = NULL;

//
// Process Hook NPI Provider.
//
ebpf_attach_provider_data_t _net_ebpf_process_hook_provider_data;

ebpf_extension_data_t _net_ebpf_extension_process_hook_provider_data = {
EBPF_ATTACH_PROVIDER_DATA_VERSION,
sizeof(_net_ebpf_process_hook_provider_data),
&_net_ebpf_process_hook_provider_data};

NPI_MODULEID DECLSPEC_SELECTANY _ebpf_process_hook_provider_moduleid = {sizeof(NPI_MODULEID), MIT_GUID, {0}};

static net_ebpf_extension_hook_provider_t* _ebpf_process_hook_provider_context = NULL;

//
// Client attach/detach handler routines.
//

static ebpf_result_t
_net_ebpf_extension_process_on_client_attach(
_In_ const net_ebpf_extension_hook_client_t* attaching_client,
_In_ const net_ebpf_extension_hook_provider_t* provider_context)
{
ebpf_result_t result = EBPF_SUCCESS;

NET_EBPF_EXT_LOG_ENTRY();

UNREFERENCED_PARAMETER(attaching_client);

// Process hook allows only one client at a time.
if (net_ebpf_extension_hook_get_next_attached_client((net_ebpf_extension_hook_provider_t*)provider_context, NULL) !=
NULL) {
result = EBPF_ACCESS_DENIED;
goto Exit;
}

result = EBPF_SUCCESS;

Exit:
NET_EBPF_EXT_RETURN_RESULT(result);
}

static void
_net_ebpf_extension_process_on_client_detach(_In_ const net_ebpf_extension_hook_client_t* detaching_client)
{
UNREFERENCED_PARAMETER(detaching_client);
}

//
// NMR Registration Helper Routines.
//

NTSTATUS
net_ebpf_ext_process_register_providers()
{
NTSTATUS status = STATUS_SUCCESS;

NET_EBPF_EXT_LOG_ENTRY();

const net_ebpf_extension_program_info_provider_parameters_t program_info_provider_parameters = {
&_ebpf_process_program_info_provider_moduleid, &_ebpf_process_program_info_provider_data};
const net_ebpf_extension_hook_provider_parameters_t hook_provider_parameters = {
&_ebpf_process_hook_provider_moduleid, &_net_ebpf_extension_process_hook_provider_data};

// Set the program type as the provider module id.
_ebpf_process_program_info_provider_moduleid.Guid = EBPF_PROGRAM_TYPE_PROCESS;
status = net_ebpf_extension_program_info_provider_register(
&program_info_provider_parameters, &_ebpf_process_program_info_provider_context);
if (!NT_SUCCESS(status)) {
NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS(
NET_EBPF_EXT_TRACELOG_LEVEL_ERROR,
NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS,
"net_ebpf_extension_program_info_provider_register",
status);
goto Exit;
}

_net_ebpf_process_hook_provider_data.supported_program_type = EBPF_PROGRAM_TYPE_PROCESS;
// Set the attach type as the provider module id.
_ebpf_process_hook_provider_moduleid.Guid = EBPF_ATTACH_TYPE_PROCESS;
_net_ebpf_process_hook_provider_data.bpf_attach_type = BPF_ATTACH_TYPE_PROCESS;
_net_ebpf_process_hook_provider_data.link_type = BPF_LINK_TYPE_PLAIN;
status = net_ebpf_extension_hook_provider_register(
&hook_provider_parameters,
_net_ebpf_extension_process_on_client_attach,
_net_ebpf_extension_process_on_client_detach,
NULL,
&_ebpf_process_hook_provider_context);
if (status != EBPF_SUCCESS) {
NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS(
NET_EBPF_EXT_TRACELOG_LEVEL_ERROR,
NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS,
"net_ebpf_extension_hook_provider_register",
status);
goto Exit;
}

Exit:
if (!NT_SUCCESS(status)) {
net_ebpf_ext_process_unregister_providers();
}
NET_EBPF_EXT_RETURN_NTSTATUS(status);
}

void
net_ebpf_ext_process_unregister_providers()
{
if (_ebpf_process_hook_provider_context) {
net_ebpf_extension_hook_provider_unregister(_ebpf_process_hook_provider_context);
_ebpf_process_hook_provider_context = NULL;
}
if (_ebpf_process_program_info_provider_context) {
net_ebpf_extension_program_info_provider_unregister(_ebpf_process_program_info_provider_context);
_ebpf_process_program_info_provider_context = NULL;
}
}

static ebpf_result_t
_ebpf_process_context_create(
_In_reads_bytes_opt_(data_size_in) const uint8_t* data_in,
size_t data_size_in,
_In_reads_bytes_opt_(context_size_in) const uint8_t* context_in,
size_t context_size_in,
_Outptr_ void** context)
{
NET_EBPF_EXT_LOG_ENTRY();
ebpf_result_t result;
process_md_t* process_context = NULL;

*context = NULL;

if (context_in == NULL || context_size_in < sizeof(process_md_t)) {
NET_EBPF_EXT_LOG_MESSAGE(
NET_EBPF_EXT_TRACELOG_LEVEL_ERROR, NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, "Context is required");
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}

process_context =
(process_md_t*)ExAllocatePoolUninitialized(NonPagedPoolNx, sizeof(process_md_t), NET_EBPF_EXTENSION_POOL_TAG);
NET_EBPF_EXT_BAIL_ON_ALLOC_FAILURE_RESULT(
NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, process_context, "process_context", result);

// Copy the context from the caller.
memcpy(process_context, context_in, sizeof(process_md_t));

// Replace the process_id_start and process_id_end with pointers to data_in.
process_context->process_id_end = (uint8_t*)data_in;
process_context->process_id_end = (uint8_t*)data_in + data_size_in;

*context = process_context;
process_context = NULL;
result = EBPF_SUCCESS;

Exit:
if (process_context) {
ExFreePool(process_context);
process_context = NULL;
}
NET_EBPF_EXT_RETURN_RESULT(result);
}

static void
_ebpf_process_context_destroy(
_In_opt_ void* context,
_Out_writes_bytes_to_(*data_size_out, *data_size_out) uint8_t* data_out,
_Inout_ size_t* data_size_out,
_Out_writes_bytes_to_(*context_size_out, *context_size_out) uint8_t* context_out,
_Inout_ size_t* context_size_out)
{
NET_EBPF_EXT_LOG_ENTRY();

process_md_t* process_context = (process_md_t*)context;
process_md_t* process_context_out = (process_md_t*)context_out;

if (!process_context) {
goto Exit;
}

if (context_out != NULL && *context_size_out >= sizeof(process_md_t)) {
// Copy the context to the caller.
memcpy(process_context_out, process_context, sizeof(process_md_t));

// Zero out the process_id_start and process_id_end.
process_context_out->process_id_start = 0;
process_context_out->process_id_end = 0;
*context_size_out = sizeof(process_md_t);
} else {
*context_size_out = 0;
}

// Copy the process_id to the data_out.
if (data_out != NULL &&
*data_size_out >= (size_t)(process_context->process_id_end - process_context->process_id_start)) {
memcpy(
data_out,
process_context->process_id_start,
process_context->process_id_end - process_context->process_id_start);
*data_size_out = process_context->process_id_end - process_context->process_id_start;
} else {
*data_size_out = 0;
}

ExFreePool(process_context);

Exit:
NET_EBPF_EXT_LOG_EXIT();
}
Loading

0 comments on commit bdd71d2

Please sign in to comment.