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:
Poorna Gaddehosur 2021-02-09 01:16:52 +00:00
Родитель 049b1c3e3f
Коммит f3ff7d06c3
11 изменённых файлов: 698 добавлений и 143 удалений

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

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