ebpf-for-windows/netebpfext/net_ebpf_ext_drv.c

175 строки
4.6 KiB
C

// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
/*++
Abstract:
WDF based driver that does the following:
1. Registers a set of WFP callouts.
2. Registers as an eBPF program information provider and hook provider.
Environment:
Kernel mode
--*/
// ntddk.h needs to be included first due to inter header dependencies on Windows.
#include <ntddk.h>
#pragma warning(push)
#pragma warning(disable : 4201) // unnamed struct/union
#include <fwpmk.h>
#include <fwpsk.h>
#pragma warning(pop)
#include <netiodef.h>
#include <wdf.h>
#include "ebpf_platform.h"
#include "net_ebpf_ext.h"
#define NET_EBPF_EXT_DEVICE_NAME L"\\Device\\NetEbpfExt"
// Driver global variables
static DEVICE_OBJECT* _net_ebpf_ext_driver_device_object;
static BOOLEAN _net_ebpf_ext_driver_unloading_flag = FALSE;
//
// Pre-Declarations
//
DRIVER_INITIALIZE DriverEntry;
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_unloading_flag = TRUE;
net_ebpf_ext_program_info_provider_unregister();
net_ebpf_ext_unregister_providers();
net_ebpf_ext_unregister_callouts();
}
//
// Create a basic WDF driver, set up the device object
// for a callout driver and register with NMR.
//
static NTSTATUS
__net_ebpf_ext_driver_initialize_objects(
_Inout_ DRIVER_OBJECT* driver_object,
_In_ const UNICODE_STRING* registry_path,
_Out_ WDFDRIVER* driver,
_Out_ WDFDEVICE* device)
{
NTSTATUS status;
WDF_DRIVER_CONFIG driver_configuration;
PWDFDEVICE_INIT device_initialize = NULL;
UNICODE_STRING ebpf_device_name;
BOOLEAN device_create_flag = FALSE;
WDF_DRIVER_CONFIG_INIT(&driver_configuration, WDF_NO_EVENT_CALLBACK);
driver_configuration.DriverInitFlags |= WdfDriverInitNonPnpDriver;
driver_configuration.EvtDriverUnload = __net_ebpf_ext_driver_unload;
status = WdfDriverCreate(driver_object, registry_path, WDF_NO_OBJECT_ATTRIBUTES, &driver_configuration, driver);
if (!NT_SUCCESS(status)) {
goto Exit;
}
device_initialize = WdfControlDeviceInitAllocate(
*driver,
&SDDL_DEVOBJ_SYS_ALL_ADM_ALL // only kernel/system and administrators.
);
if (!device_initialize) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
WdfDeviceInitSetDeviceType(device_initialize, FILE_DEVICE_NETWORK);
WdfDeviceInitSetCharacteristics(device_initialize, FILE_DEVICE_SECURE_OPEN, FALSE);
WdfDeviceInitSetCharacteristics(device_initialize, FILE_AUTOGENERATED_DEVICE_NAME, TRUE);
RtlInitUnicodeString(&ebpf_device_name, NET_EBPF_EXT_DEVICE_NAME);
status = WdfDeviceInitAssignName(device_initialize, &ebpf_device_name);
if (!NT_SUCCESS(status)) {
goto Exit;
}
status = WdfDeviceCreate(&device_initialize, WDF_NO_OBJECT_ATTRIBUTES, device);
if (!NT_SUCCESS(status)) {
// do not free if any other call
// after WdfDeviceCreate fails.
WdfDeviceInitFree(device_initialize);
device_initialize = NULL;
goto Exit;
}
device_create_flag = TRUE;
status = net_ebpf_ext_register_providers();
if (!NT_SUCCESS(status)) {
goto Exit;
}
status = net_ebpf_ext_program_info_provider_register();
if (!NT_SUCCESS(status)) {
goto Exit;
}
WdfControlFinishInitializing(*device);
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;
}
NTSTATUS
DriverEntry(_In_ DRIVER_OBJECT* driver_object, _In_ UNICODE_STRING* registry_path)
{
NTSTATUS status;
WDFDRIVER driver;
WDFDEVICE device;
// Request NX Non-Paged Pool when available
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "NetEbpfExt: DriverEntry\n"));
status = __net_ebpf_ext_driver_initialize_objects(driver_object, registry_path, &driver, &device);
if (!NT_SUCCESS(status)) {
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:
if (!NT_SUCCESS(status)) {
net_ebpf_ext_unregister_callouts();
}
return status;
}