Merged PR 4090115: modifies driver to receive opcode based commands from usermode for load/unload/attach/detach
- adds support to receive opcode based commands from usermode for load/unload/attach/detach - parses layerdata from wfp classify - passes in xdp_md like context to usermode code from the classify context - modified test tool to test these changes - adds a droppacket.c code with instructions to illustrate xdp and ctx based evaluation for dosp. Related work items: #9115665
This commit is contained in:
Родитель
049b1c3e3f
Коммит
f3ff7d06c3
|
@ -149,7 +149,7 @@
|
|||
<PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SolutionDir)..\api\;$(SolutionDir)EbpfCore\</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
|
||||
<ExceptionHandling>
|
||||
</ExceptionHandling>
|
||||
|
@ -168,7 +168,7 @@
|
|||
<PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SolutionDir)..\api\;$(SolutionDir)EbpfCore\</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
|
||||
<ExceptionHandling>
|
||||
</ExceptionHandling>
|
||||
|
@ -231,7 +231,9 @@
|
|||
<FilesToPackage Include="$(TargetPath)" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\api\protocol.h" />
|
||||
<ClInclude Include="ebpf_l2_hook.h" />
|
||||
<ClInclude Include="types.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
<ClInclude Include="ebpf_l2_hook.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\api\protocol.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Inf Include="EbpfCore.inf">
|
||||
|
|
|
@ -24,9 +24,10 @@ Environment:
|
|||
#pragma warning(pop)
|
||||
|
||||
#include <fwpmk.h>
|
||||
|
||||
#include <netiodef.h>
|
||||
#include "ebpf_l2_hook.h"
|
||||
|
||||
#include "types.h"
|
||||
#include "protocol.h"
|
||||
|
||||
// Driver global variables
|
||||
|
||||
|
@ -35,7 +36,10 @@ BOOLEAN gDriverUnloading = FALSE;
|
|||
DRIVER_INITIALIZE DriverEntry;
|
||||
EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;
|
||||
DWORD gError = 0;
|
||||
DWORD gSuccess = 0;
|
||||
|
||||
LIST_ENTRY gUserCodeList;
|
||||
KSPIN_LOCK gUserCodeLock;
|
||||
UINT64 gHandle = 0;
|
||||
|
||||
// Typedefs
|
||||
typedef enum
|
||||
|
@ -47,7 +51,6 @@ typedef VOID(WINAPI* FUNCTION_TYPE) (VOID);
|
|||
typedef DWORD(WINAPI* FUNCTION_TYPE1) (DWORD);
|
||||
typedef DWORD(WINAPI* FUNCTION_TYPE2) (PVOID, PVOID);
|
||||
|
||||
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
|
@ -69,6 +72,11 @@ PCWSTR EbpfSymbolicDeviceName = L"\\GLOBAL??\\EbpfIoDevice";
|
|||
//
|
||||
// Pre-Declarations
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
UnloadCode(
|
||||
_In_ uint64_t handle,
|
||||
_In_ BOOLEAN force);
|
||||
VOID
|
||||
EbpfCoreEvtIoDeviceControl(
|
||||
_In_ WDFQUEUE queue,
|
||||
|
@ -91,6 +99,8 @@ EvtDriverUnload(
|
|||
gDriverUnloading = TRUE;
|
||||
|
||||
EbpfHookUnregisterCallouts();
|
||||
|
||||
UnloadCode(0, TRUE);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -214,6 +224,9 @@ EbpfCoreInitDriverObjects(
|
|||
|
||||
WdfControlFinishInitializing(*pDevice);
|
||||
|
||||
KeInitializeSpinLock(&gUserCodeLock);
|
||||
InitializeListHead(&gUserCodeList);
|
||||
|
||||
Exit:
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
|
@ -245,71 +258,220 @@ int DropPacket(unsigned int protocol)
|
|||
}
|
||||
}
|
||||
|
||||
// Run user mode code provided in an input buffer
|
||||
// Assumes code is contained in a page size of 4k
|
||||
VOID
|
||||
ExecuteCode(_In_ PVOID inputBuffer)
|
||||
NTSTATUS
|
||||
CheckAndAttachCodeToHook(
|
||||
_In_ struct EbpfOpAttachDetachRequest* attachRequest
|
||||
)
|
||||
{
|
||||
PVOID buffer = NULL;
|
||||
PMDL mdl = NULL;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
FUNCTION_TYPE1 funcPtr1;
|
||||
DWORD result = 0;
|
||||
KIRQL irql;
|
||||
UserCode* code = NULL;
|
||||
|
||||
KeAcquireSpinLock(&gUserCodeLock, &irql);
|
||||
LIST_ENTRY* listEntry = gUserCodeList.Flink;
|
||||
while (listEntry != &gUserCodeList)
|
||||
{
|
||||
code = CONTAINING_RECORD(listEntry, UserCode, entry);
|
||||
if (attachRequest->handle == code->handle)
|
||||
{
|
||||
code->attached = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
listEntry = listEntry->Flink;
|
||||
}
|
||||
KeReleaseSpinLock(&gUserCodeLock, irql);
|
||||
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "EbpfCore: AttachCodeToHook 0x%lx handle \n", attachRequest->handle));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
DetachCodeFromHook(
|
||||
_In_ struct EbpfOpAttachDetachRequest* detachRequest
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
KIRQL irql;
|
||||
UserCode* code = NULL;
|
||||
|
||||
KeAcquireSpinLock(&gUserCodeLock, &irql);
|
||||
LIST_ENTRY* listEntry = gUserCodeList.Flink;
|
||||
while (listEntry != &gUserCodeList)
|
||||
{
|
||||
code = CONTAINING_RECORD(listEntry, UserCode, entry);
|
||||
if (detachRequest->handle == code->handle)
|
||||
{
|
||||
code->attached = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
listEntry = listEntry->Flink;
|
||||
}
|
||||
KeReleaseSpinLock(&gUserCodeLock, irql);
|
||||
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "EbpfCore: DetachCodeFromHook 0x%lx handle \n", detachRequest->handle));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
UnloadCode(
|
||||
_In_ uint64_t handle,
|
||||
_In_ BOOLEAN force)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
KIRQL irql;
|
||||
UserCode* code = NULL;
|
||||
BOOLEAN found = FALSE;
|
||||
|
||||
KeAcquireSpinLock(&gUserCodeLock, &irql);
|
||||
LIST_ENTRY* listEntry = gUserCodeList.Flink;
|
||||
while (listEntry->Flink != &gUserCodeList)
|
||||
{
|
||||
code = CONTAINING_RECORD(listEntry, UserCode, entry);
|
||||
listEntry = listEntry->Flink;
|
||||
if (force || handle == code->handle)
|
||||
{
|
||||
found = TRUE;
|
||||
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "EbpfCore: UnloadCode: 0x%lx handle: 0x%lx. \n", code, code->handle));
|
||||
RemoveEntryList(&code->entry);
|
||||
if (code != NULL)
|
||||
{
|
||||
ExFreePool(code);
|
||||
}
|
||||
|
||||
if (!force)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
KeReleaseSpinLock(&gUserCodeLock, irql);
|
||||
if (!force && !found)
|
||||
{
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "EbpfCore: UnloadCode: failed to find handle 0x%lx \n",handle));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
AllocateAndLoadCode(
|
||||
_In_ struct EbpfOpLoadRequest* inputRequest,
|
||||
_Out_ struct EbpfOpLoadReply* loadReply)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PVOID buffer = NULL;
|
||||
UINT16 codeSize = 0;
|
||||
KIRQL irql;
|
||||
UserCode* code = NULL;
|
||||
|
||||
// validate
|
||||
if (inputRequest->header.length > gBufferLength)
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (loadReply == NULL)
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// allocate
|
||||
codeSize = inputRequest->header.length;
|
||||
buffer = ExAllocatePool2(
|
||||
POOL_FLAG_NON_PAGED_EXECUTE,
|
||||
gBufferLength,
|
||||
codeSize + sizeof(UserCode),
|
||||
ebpfPoolTag
|
||||
);
|
||||
|
||||
if (buffer == NULL) {
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
goto Cleanup;
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
mdl = IoAllocateMdl(
|
||||
buffer,
|
||||
(ULONG) gBufferLength,
|
||||
FALSE,
|
||||
TRUE,
|
||||
NULL
|
||||
);
|
||||
if (mdl == NULL) {
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
goto Cleanup;
|
||||
}
|
||||
// copy and hang on to user code
|
||||
code = buffer;
|
||||
buffer = (byte*)buffer + sizeof(UserCode);
|
||||
RtlCopyMemory(buffer, (PUCHAR)inputRequest->machine_code, codeSize);
|
||||
code->code = buffer;
|
||||
|
||||
MmBuildMdlForNonPagedPool(mdl);
|
||||
// todo: polish handle allocation logic
|
||||
code->handle = (0xffff | gHandle++);
|
||||
|
||||
PUCHAR VPage = (UCHAR*)buffer;
|
||||
RtlCopyMemory(VPage, (PUCHAR)inputBuffer, gBufferLength);
|
||||
funcPtr1 = (FUNCTION_TYPE1)VPage;
|
||||
KeAcquireSpinLock(&gUserCodeLock, &irql);
|
||||
InsertTailList(&gUserCodeList, &code->entry);
|
||||
KeReleaseSpinLock(&gUserCodeLock, irql);
|
||||
|
||||
__try {
|
||||
// construct the response
|
||||
loadReply->handle = code->handle;
|
||||
loadReply->header.id = load_code;
|
||||
loadReply->header.length = sizeof(struct EbpfOpLoadReply);
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "EbpfCore: AllocateAndLoadCode code: 0x%lx handle: 0x%lx. \n", code, code->handle));
|
||||
|
||||
result = (*funcPtr1)(gSuccess);
|
||||
gSuccess++;
|
||||
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
Done:
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
gError++;
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "EbpfCore: AllocateAndLoadCode code failed %d\n", status));
|
||||
}
|
||||
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "EbpfCore: ExecuteCode. gSuccess %d, gError %d\n", gSuccess, gError));
|
||||
return status;
|
||||
}
|
||||
|
||||
Cleanup:
|
||||
// Returns xdp_action
|
||||
// permit = 1
|
||||
// drop = 2
|
||||
UINT32
|
||||
ExecuteCodeAtHook(
|
||||
_In_ void* buffer
|
||||
)
|
||||
{
|
||||
KIRQL irql;
|
||||
UserCode* code = NULL;
|
||||
XDP_HOOK funcPtr;
|
||||
DWORD result = permit;
|
||||
BOOLEAN found = FALSE;
|
||||
|
||||
if (mdl != NULL)
|
||||
xdp_md ctx = {0};
|
||||
ctx.data = (UINT64) buffer;
|
||||
ctx.data_end = (UINT64) ((char *) buffer + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER));
|
||||
|
||||
KeAcquireSpinLock(&gUserCodeLock, &irql);
|
||||
|
||||
LIST_ENTRY* listEntry = gUserCodeList.Flink;
|
||||
while (listEntry != &gUserCodeList)
|
||||
{
|
||||
IoFreeMdl(mdl);
|
||||
code = CONTAINING_RECORD(listEntry, UserCode, entry);
|
||||
if (code->attached)
|
||||
{
|
||||
// find the first one and run.
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
listEntry = listEntry->Flink;
|
||||
}
|
||||
|
||||
if (buffer != NULL)
|
||||
if (found)
|
||||
{
|
||||
ExFreePool(buffer);
|
||||
funcPtr = (XDP_HOOK)code->code;
|
||||
__try {
|
||||
result = (*funcPtr)(&ctx);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
gError++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
KeReleaseSpinLock(&gUserCodeLock, irql);
|
||||
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "EbpfCore: ExecuteCode. gError %d\n", gError));
|
||||
|
||||
return (UINT32)result;
|
||||
}
|
||||
|
||||
VOID
|
||||
|
@ -321,52 +483,101 @@ EbpfCoreEvtIoDeviceControl(
|
|||
_In_ ULONG ioControlCode
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
WDFDEVICE device;
|
||||
void* inputBuffer = NULL;
|
||||
void* outputBuffer = NULL;
|
||||
size_t actualInputLength;
|
||||
size_t actualOutputLength;
|
||||
struct EbpfOpHeader* inputRequest = NULL;
|
||||
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
WDFDEVICE device;
|
||||
void* inputBuffer = NULL;
|
||||
size_t actualLength;
|
||||
char* inputValue = NULL;
|
||||
UNREFERENCED_PARAMETER(outputBufferLength);
|
||||
UNREFERENCED_PARAMETER(inputBufferLength);
|
||||
|
||||
UNREFERENCED_PARAMETER(outputBufferLength);
|
||||
UNREFERENCED_PARAMETER(inputBufferLength);
|
||||
device = WdfIoQueueGetDevice(queue);
|
||||
|
||||
device = WdfIoQueueGetDevice(queue);
|
||||
switch (ioControlCode)
|
||||
{
|
||||
case IOCTL_EBPFCTL_METHOD_BUFFERED:
|
||||
// Verify that length of the input buffer supplied to the request object
|
||||
// is not zero
|
||||
if (inputBufferLength != 0)
|
||||
{
|
||||
// Retrieve the input buffer associated with the request object
|
||||
status = WdfRequestRetrieveInputBuffer(
|
||||
request, // Request object
|
||||
inputBufferLength, // Length of input buffer
|
||||
&inputBuffer, // Pointer to buffer
|
||||
&actualInputLength // Length of buffer
|
||||
);
|
||||
|
||||
switch(ioControlCode)
|
||||
{
|
||||
case IOCTL_EBPFCTL_METHOD_BUFFERED:
|
||||
// Verify that length of the input buffer supplied to the request object
|
||||
// is not zero
|
||||
if(inputBufferLength != 0)
|
||||
{
|
||||
// Retrieve the input buffer associated with the request object
|
||||
status = WdfRequestRetrieveInputBuffer(
|
||||
request, // Request object
|
||||
inputBufferLength, // Length of input buffer
|
||||
&inputBuffer, // Pointer to buffer
|
||||
&actualLength // Length of buffer
|
||||
);
|
||||
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
if(inputBuffer != NULL)
|
||||
{
|
||||
inputValue = (char *)inputBuffer;
|
||||
ExecuteCode(inputValue);
|
||||
}
|
||||
}
|
||||
else{
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "EbpfCore: Input buffer failure %d\n", status));
|
||||
goto Done;
|
||||
}
|
||||
|
||||
WdfRequestComplete(request, status);
|
||||
return;
|
||||
// Retrieve output buffer associated with the request object
|
||||
status = WdfRequestRetrieveOutputBuffer(
|
||||
request,
|
||||
outputBufferLength,
|
||||
&outputBuffer,
|
||||
&actualOutputLength
|
||||
);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "EbpfCore: Output buffer failure %d\n", status));
|
||||
goto Done;
|
||||
}
|
||||
if (inputBuffer == NULL || outputBuffer == NULL)
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (inputBuffer != NULL && outputBuffer != NULL)
|
||||
{
|
||||
|
||||
status = EbpfHookRegisterCallouts(gWdmDevice);
|
||||
// non fatal for now while testing
|
||||
|
||||
inputRequest = inputBuffer;
|
||||
switch (inputRequest->id)
|
||||
{
|
||||
case load_code:
|
||||
{
|
||||
status = AllocateAndLoadCode(
|
||||
(struct EbpfOpLoadRequest*)inputRequest,
|
||||
outputBuffer);
|
||||
break;
|
||||
}
|
||||
case unload_code:
|
||||
{
|
||||
struct EbpfOpUnloadRequest* unloadRequest;
|
||||
unloadRequest = inputBuffer;
|
||||
status = UnloadCode(unloadRequest->handle, FALSE);
|
||||
break;
|
||||
}
|
||||
case attach:
|
||||
{
|
||||
status = CheckAndAttachCodeToHook(inputBuffer);
|
||||
break;
|
||||
}
|
||||
case detach:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Done:
|
||||
WdfRequestCompleteWithInformation(request, status, outputBufferLength);
|
||||
return;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
|
@ -398,12 +609,9 @@ DriverEntry(
|
|||
|
||||
gWdmDevice = WdfDeviceWdmGetDeviceObject(device);
|
||||
|
||||
status = EbpfHookRegisterCallouts(gWdmDevice);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
EbpfHookRegisterCallouts(gWdmDevice);
|
||||
// ignore status. at boot, registration can fail.
|
||||
// we will try to re-register during prog load.
|
||||
|
||||
Exit:
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ Environment:
|
|||
#pragma warning(pop)
|
||||
|
||||
#include <fwpmk.h>
|
||||
#include <netiodef.h>
|
||||
|
||||
#include "ebpf_l2_hook.h"
|
||||
|
||||
|
@ -53,6 +54,8 @@ DEFINE_GUID(
|
|||
HANDLE gEngineHandle;
|
||||
UINT32 gL2CalloutId;
|
||||
|
||||
extern INT32 ExecuteCodeAtHook(_In_ void* ctx);
|
||||
|
||||
NTSTATUS
|
||||
EbpfHookAddFilter(
|
||||
_In_ const PWSTR filterName,
|
||||
|
@ -208,6 +211,12 @@ EbpfHookRegisterCallouts(
|
|||
|
||||
FWPM_SESSION session = { 0 };
|
||||
|
||||
if (gEngineHandle != NULL)
|
||||
{
|
||||
// already registered
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
session.flags = FWPM_SESSION_FLAG_DYNAMIC;
|
||||
|
||||
status = FwpmEngineOpen(
|
||||
|
@ -310,14 +319,52 @@ EbpfHookL2Classify(
|
|||
|
||||
-- */
|
||||
{
|
||||
FWP_ACTION_TYPE action = FWP_ACTION_PERMIT;
|
||||
UNREFERENCED_PARAMETER(inFixedValues);
|
||||
UNREFERENCED_PARAMETER(inMetaValues);
|
||||
UNREFERENCED_PARAMETER(layerData);
|
||||
UNREFERENCED_PARAMETER(classifyContext);
|
||||
UNREFERENCED_PARAMETER(filter);
|
||||
UNREFERENCED_PARAMETER(flowContext);
|
||||
|
||||
classifyOut->actionType = FWP_ACTION_PERMIT;
|
||||
NET_BUFFER_LIST* nbl = (NET_BUFFER_LIST*)layerData;
|
||||
NET_BUFFER* netBuffer = NULL;
|
||||
BYTE* mdlAddr;
|
||||
UINT32 result = 0;
|
||||
|
||||
if (nbl == NULL)
|
||||
{
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Null nbl \n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
netBuffer = NET_BUFFER_LIST_FIRST_NB(nbl);
|
||||
if (netBuffer == NULL)
|
||||
{
|
||||
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "netbuffer not present\n"));
|
||||
// nothing to do
|
||||
goto done;
|
||||
}
|
||||
|
||||
mdlAddr =
|
||||
NdisGetDataBuffer(
|
||||
netBuffer,
|
||||
sizeof(IPV4_HEADER) + max(sizeof(TCP_HEADER), sizeof(UDP_HEADER)),
|
||||
NULL,
|
||||
sizeof(UINT16),
|
||||
0);
|
||||
|
||||
// execute code at hook.
|
||||
result = ExecuteCodeAtHook(mdlAddr);
|
||||
if (result == 1)
|
||||
{
|
||||
action = FWP_ACTION_PERMIT;
|
||||
}
|
||||
else if (result == 2)
|
||||
{
|
||||
action = FWP_ACTION_BLOCK;
|
||||
}
|
||||
|
||||
done:
|
||||
classifyOut->actionType = action;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -352,4 +399,3 @@ EbpfHookL2FlowDelete(
|
|||
UNREFERENCED_PARAMETER(flowContext);
|
||||
return;
|
||||
}
|
||||
|
|
@ -15,8 +15,43 @@ Environment:
|
|||
|
||||
#ifndef _EBPF_L2HOOK_H_
|
||||
#define _EBPF_L2HOOK_H_
|
||||
#include "types.h"
|
||||
|
||||
// XDP like hook
|
||||
typedef struct xdp_md_ {
|
||||
UINT64 data; /* 0 8 */
|
||||
UINT64 data_end; /* 8 8 */
|
||||
UINT64 data_meta; /* 16 8 */
|
||||
|
||||
/* size: 12, cachelines: 1, members: 3 */
|
||||
/* last cacheline: 12 bytes */
|
||||
} xdp_md;
|
||||
|
||||
typedef DWORD(WINAPI* XDP_HOOK) (PVOID);
|
||||
|
||||
typedef enum xdp_action_
|
||||
{
|
||||
permit = 1,
|
||||
drop = 2
|
||||
} xdp_action;
|
||||
|
||||
typedef struct {
|
||||
LIST_ENTRY entry;
|
||||
|
||||
// pointer to code buffer
|
||||
byte* code;
|
||||
|
||||
// handle required for attach/detach/unload
|
||||
uint64_t handle;
|
||||
|
||||
// is attached ?
|
||||
BOOLEAN attached;
|
||||
} UserCode;
|
||||
|
||||
// Externs
|
||||
extern LIST_ENTRY gUserCodeList;
|
||||
extern KSPIN_LOCK gUserCodeLock;
|
||||
|
||||
extern UINT32 gL2CalloutId;
|
||||
extern BOOLEAN gDriverUnloading;
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#define uint8_t UINT8
|
||||
#define uint16_t UINT16
|
||||
#define uint32_t UINT32
|
||||
#define uint64_t UINT64
|
||||
|
||||
typedef struct UDP_HEADER_ {
|
||||
UINT16 srcPort;
|
||||
UINT16 destPort;
|
||||
UINT16 length;
|
||||
UINT16 checksum;
|
||||
} UDP_HEADER;
|
||||
|
||||
typedef struct _TCP_HEADER
|
||||
{
|
||||
USHORT SourcePort;
|
||||
USHORT DestinationPort;
|
||||
ULONG SequenceNumber;
|
||||
ULONG AckNumber;
|
||||
USHORT OffsetAndFlags;
|
||||
USHORT WindowSize;
|
||||
USHORT Checksum;
|
||||
USHORT UrgentPointer;
|
||||
} TCP_HEADER, * PTCP_HEADER;
|
|
@ -4,6 +4,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strsafe.h>
|
||||
#include "..\EbpfCore\types.h"
|
||||
#include "protocol.h"
|
||||
|
||||
// Device type
|
||||
#define EBPF_IOCTL_TYPE FILE_DEVICE_NETWORK
|
||||
|
@ -16,16 +18,38 @@ int main(
|
|||
_In_ ULONG argc,
|
||||
_In_reads_(argc) PCHAR argv[]
|
||||
)
|
||||
|
||||
{
|
||||
HANDLE deviceHandle;
|
||||
HANDLE deviceHandle = INVALID_HANDLE_VALUE;
|
||||
DWORD error = NO_ERROR;
|
||||
LPCWSTR ebpfDeviceName = L"\\\\.\\EbpfIoDevice";
|
||||
ULONG bytesReturned;
|
||||
void* inputBuffer = NULL;
|
||||
struct EbpfOpHeader* header = NULL;
|
||||
int action = 0;
|
||||
UINT64 inputHandle;
|
||||
DWORD inputBufferLength;
|
||||
struct EbpfOpLoadRequest* loadRequest;
|
||||
struct EbpfOpLoadReply outputBuffer = { 0 };
|
||||
DWORD outputBufferLength = sizeof(struct EbpfOpLoadReply);
|
||||
UINT64 handle = 0;
|
||||
|
||||
UNREFERENCED_PARAMETER(argc);
|
||||
UNREFERENCED_PARAMETER(argv);
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("usage: ebpftool.exe <load(0)/attach(1)/unload(2)> <handle>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
action = atoi(argv[1]);
|
||||
if (action != 0 )
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
printf("handle required for attach and unload.\n");
|
||||
return;
|
||||
}
|
||||
inputHandle = atoi(argv[2]);
|
||||
}
|
||||
|
||||
deviceHandle = CreateFile(ebpfDeviceName,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
|
@ -34,56 +58,159 @@ int main(
|
|||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (deviceHandle == INVALID_HANDLE_VALUE) {
|
||||
if (deviceHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
error = GetLastError();
|
||||
printf("Error: CreatFile Failed : %d\n", error);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Read code from file later.
|
||||
llvm-objdump -d dropjit.o
|
||||
|
||||
dropjit.o: file format coff-x86-64
|
||||
|
||||
|
||||
Disassembly of section :
|
||||
|
||||
0000000000000000 <DropPacket>:
|
||||
0: 89 4c 24 08 movl %ecx, 8(%rsp)
|
||||
4: 83 7c 24 08 11 cmpl $17, 8(%rsp)
|
||||
9: 75 06 jne 0x11 <DropPacket+0x11>
|
||||
b: 33 c0 xorl %eax, %eax
|
||||
d: eb 07 jmp 0x16 <DropPacket+0x16>
|
||||
f: eb 05 jmp 0x16 <DropPacket+0x16>
|
||||
11: b8 01 00 00 00 movl $1, %eax
|
||||
16: c3 retq
|
||||
0: 48 8b 01 movq (%rcx), %rax
|
||||
3: 48 8b 49 08 movq 8(%rcx), %rcx
|
||||
7: 48 8d 50 1c leaq 28(%rax), %rdx
|
||||
b: 48 39 ca cmpq %rcx, %rdx
|
||||
e: 77 1d ja 0x2d <DropPacket+0x2d>
|
||||
10: 48 8d 50 08 leaq 8(%rax), %rdx
|
||||
14: 48 39 ca cmpq %rcx, %rdx
|
||||
17: 77 14 ja 0x2d <DropPacket+0x2d>
|
||||
19: 80 78 09 11 cmpb $17, 9(%rax)
|
||||
1d: 75 0e jne 0x2d <DropPacket+0x2d>
|
||||
1f: 66 83 78 18 01 cmpw $1, 24(%rax)
|
||||
24: b8 01 00 00 00 movl $1, %eax
|
||||
29: 83 d0 00 adcl $0, %eax
|
||||
2c: c3 retq
|
||||
2d: b8 01 00 00 00 movl $1, %eax
|
||||
32: c3 retq
|
||||
|
||||
*/
|
||||
char inputBuffer[100] =
|
||||
{
|
||||
0x89, 0x4c, 0x24, 0x08,
|
||||
0x83, 0x7c, 0x24, 0x08, 0x11,
|
||||
0x75,0x06,
|
||||
0x33, 0xc0,
|
||||
0xeb,0x07,
|
||||
0xeb, 0x05,
|
||||
0xb8, 0x01, 00, 00, 00,
|
||||
0xc3
|
||||
};
|
||||
|
||||
DWORD inputBufferLength = 0x17;
|
||||
printf("InputBuffer Pointer = %p, BufLength = %Iu\n", inputBuffer,
|
||||
sizeof(inputBuffer));
|
||||
|
||||
error = DeviceIoControl(
|
||||
deviceHandle,
|
||||
(DWORD)IOCTL_EBPFCTL_METHOD_BUFFERED,
|
||||
&inputBuffer,
|
||||
(DWORD)inputBufferLength,
|
||||
NULL,
|
||||
0,
|
||||
&bytesReturned,
|
||||
NULL);
|
||||
if (!error)
|
||||
char code[100] =
|
||||
{
|
||||
error = GetLastError();
|
||||
printf("Error in DeviceIoControl : %d", error);
|
||||
0x48, 0x8b, 0x1,
|
||||
0x48, 0x8b, 0x49, 0x8,
|
||||
0x48, 0x8d, 0x50, 0x1c,
|
||||
0x48, 0x39, 0xca,
|
||||
0x77, 0x1d,
|
||||
0x48, 0x8d, 0x50, 0x08,
|
||||
0x48, 0x39, 0xca,
|
||||
0x77, 0x14,
|
||||
0x80, 0x78, 0x09, 0x11,
|
||||
0x75, 0x0e,
|
||||
0x66, 0x83 ,0x78 ,0x18 ,0x01,
|
||||
0xb8, 0x01, 00, 00, 00,
|
||||
0x83, 0xd0, 0x0,
|
||||
0xc3,
|
||||
0xb8, 0x01, 00, 00, 00,
|
||||
0xc3
|
||||
};
|
||||
inputBufferLength = sizeof(code) + sizeof(struct EbpfOpLoadRequest);
|
||||
|
||||
inputBuffer = malloc(inputBufferLength);
|
||||
if (inputBuffer == NULL)
|
||||
{
|
||||
error = ERROR_OUTOFMEMORY;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (action == 0) //load
|
||||
{
|
||||
loadRequest = inputBuffer;
|
||||
loadRequest->header.id = load_code;
|
||||
loadRequest->header.length = inputBufferLength;
|
||||
RtlCopyMemory(&loadRequest->machine_code, code, sizeof(code));
|
||||
|
||||
|
||||
error = DeviceIoControl(
|
||||
deviceHandle,
|
||||
(DWORD)IOCTL_EBPFCTL_METHOD_BUFFERED,
|
||||
inputBuffer,
|
||||
(DWORD)inputBufferLength,
|
||||
&outputBuffer,
|
||||
outputBufferLength,
|
||||
&bytesReturned,
|
||||
NULL);
|
||||
if (!error)
|
||||
{
|
||||
error = GetLastError();
|
||||
printf("Error in DeviceIoControl : %d", error);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
handle = outputBuffer.handle;
|
||||
printf("Load succeeded. Program handle %lld\n", handle);
|
||||
|
||||
}
|
||||
else if (action == 1) // attach
|
||||
{
|
||||
// attach.
|
||||
header = (struct EbpfOpHeader*)inputBuffer;
|
||||
header->id = attach;
|
||||
struct EbpfOpAttachDetachRequest* attachRequest = inputBuffer;
|
||||
attachRequest->handle = inputHandle;
|
||||
attachRequest->hook = 1;
|
||||
|
||||
error = DeviceIoControl(
|
||||
deviceHandle,
|
||||
(DWORD)IOCTL_EBPFCTL_METHOD_BUFFERED,
|
||||
inputBuffer,
|
||||
(DWORD)inputBufferLength,
|
||||
&outputBuffer,
|
||||
outputBufferLength,
|
||||
&bytesReturned,
|
||||
NULL);
|
||||
if (!error)
|
||||
{
|
||||
error = GetLastError();
|
||||
printf("Error in DeviceIoControl : %d", error);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
printf("Attach succeeded\n");
|
||||
}
|
||||
else if (action == 2) // unload
|
||||
{
|
||||
header = (struct EbpfOpHeader*)inputBuffer;
|
||||
struct EbpfOpUnloadRequest* unloadRequest = inputBuffer;
|
||||
header->id = unload_code;
|
||||
unloadRequest->handle = inputHandle;
|
||||
|
||||
error = DeviceIoControl(
|
||||
deviceHandle,
|
||||
(DWORD)IOCTL_EBPFCTL_METHOD_BUFFERED,
|
||||
inputBuffer,
|
||||
(DWORD)inputBufferLength,
|
||||
&outputBuffer,
|
||||
outputBufferLength,
|
||||
&bytesReturned,
|
||||
NULL);
|
||||
if (!error)
|
||||
{
|
||||
error = GetLastError();
|
||||
printf("Error in DeviceIoControl : %d", error);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
printf("Unload succeeded\n");
|
||||
}
|
||||
Exit:
|
||||
if (inputBuffer != NULL)
|
||||
{
|
||||
free(inputBuffer);
|
||||
}
|
||||
|
||||
if (deviceHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(deviceHandle);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
|
@ -118,6 +118,7 @@
|
|||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)..\api\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -132,6 +133,7 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)..\api\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -143,6 +145,10 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="EbpfTool.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\api\protocol.h" />
|
||||
<ClInclude Include="..\EbpfCore\types.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
|
|
@ -19,4 +19,12 @@
|
|||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\api\protocol.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\EbpfCore\types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,86 @@
|
|||
// clang -O2 -Wall -c droppacket.c -o dropjit.o
|
||||
//
|
||||
// For bpf code: clang -target bpf -O2 -Wall -c droppacket.c -o droppacket.o
|
||||
// this passes the checker
|
||||
|
||||
#pragma clang section text="xdp"
|
||||
|
||||
typedef unsigned long long __u64;
|
||||
typedef unsigned long __u32;
|
||||
typedef unsigned short __u16;
|
||||
typedef unsigned char __u8;
|
||||
|
||||
typedef struct xdp_md_
|
||||
{
|
||||
__u64 data;
|
||||
__u64 data_end;
|
||||
__u64 data_meta;
|
||||
} xdp_md;
|
||||
|
||||
typedef struct _IPV4_HEADER {
|
||||
union {
|
||||
__u8 VersionAndHeaderLength; // Version and header length.
|
||||
struct {
|
||||
__u8 HeaderLength : 4;
|
||||
__u8 Version : 4;
|
||||
};
|
||||
};
|
||||
union {
|
||||
__u8 TypeOfServiceAndEcnField; // Type of service & ECN (RFC 3168).
|
||||
struct {
|
||||
__u8 EcnField : 2;
|
||||
__u8 TypeOfService : 6;
|
||||
};
|
||||
};
|
||||
__u16 TotalLength; // Total length of datagram.
|
||||
__u16 Identification;
|
||||
union {
|
||||
__u16 FlagsAndOffset; // Flags and fragment offset.
|
||||
struct {
|
||||
__u16 DontUse1 : 5; // High bits of fragment offset.
|
||||
__u16 MoreFragments : 1;
|
||||
__u16 DontFragment : 1;
|
||||
__u16 Reserved : 1;
|
||||
__u16 DontUse2 : 8; // Low bits of fragment offset.
|
||||
};
|
||||
};
|
||||
__u8 TimeToLive;
|
||||
__u8 Protocol;
|
||||
__u16 HeaderChecksum;
|
||||
__u32 SourceAddress;
|
||||
__u32 DestinationAddress;
|
||||
} IPV4_HEADER, *PIPV4_HEADER;
|
||||
|
||||
typedef struct UDP_HEADER_ {
|
||||
__u16 srcPort;
|
||||
__u16 destPort;
|
||||
__u16 length;
|
||||
__u16 checksum;
|
||||
} UDP_HEADER;
|
||||
|
||||
|
||||
int DropPacket(xdp_md* ctx)
|
||||
{
|
||||
void *data_end = (void *)(long long)ctx->data_end;
|
||||
void *data = (void *)(long long)ctx->data;
|
||||
UDP_HEADER* udphdr;
|
||||
IPV4_HEADER* iphdr = data;
|
||||
int rc = 1;
|
||||
if (data + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) > data_end)
|
||||
goto Done;
|
||||
|
||||
// udp
|
||||
if (iphdr->Protocol == 17)
|
||||
{
|
||||
udphdr = (UDP_HEADER* )(data + sizeof(IPV4_HEADER));
|
||||
if (data + sizeof(UDP_HEADER) > data_end)
|
||||
goto Done;
|
||||
|
||||
if (udphdr->length ==0)
|
||||
{
|
||||
rc = 2;
|
||||
}
|
||||
}
|
||||
Done:
|
||||
return rc;
|
||||
}
|
|
@ -4,14 +4,15 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
enum class EbpfOperation {
|
||||
typedef enum EbpfOperation_ {
|
||||
evidence,
|
||||
resolve_helper,
|
||||
resolve_map,
|
||||
load_code,
|
||||
unload_code,
|
||||
attach,
|
||||
detach,
|
||||
};
|
||||
} EbpfOperation;
|
||||
|
||||
struct EbpfOpHeader {
|
||||
uint16_t length;
|
||||
|
@ -53,6 +54,11 @@ struct EbpfOpLoadRequest {
|
|||
uint8_t machine_code[1];
|
||||
};
|
||||
|
||||
struct EbpfOpUnloadRequest {
|
||||
struct EbpfOpHeader header;
|
||||
uint64_t handle;
|
||||
};
|
||||
|
||||
struct EbpfOpLoadReply {
|
||||
struct EbpfOpHeader header;
|
||||
uint64_t handle;
|
||||
|
|
Загрузка…
Ссылка в новой задаче