diff --git a/src/ebpf/core/EbpfCore/EbpfCore.vcxproj b/src/ebpf/core/EbpfCore/EbpfCore.vcxproj
index 20e2e4e1d..0d5724fd5 100644
--- a/src/ebpf/core/EbpfCore/EbpfCore.vcxproj
+++ b/src/ebpf/core/EbpfCore/EbpfCore.vcxproj
@@ -149,7 +149,7 @@
%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO
- %(AdditionalIncludeDirectories);$(DDK_INC_PATH)
+ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SolutionDir)..\api\;$(SolutionDir)EbpfCore\
%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO
@@ -168,7 +168,7 @@
%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO
- %(AdditionalIncludeDirectories);$(DDK_INC_PATH)
+ %(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SolutionDir)..\api\;$(SolutionDir)EbpfCore\
%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO
@@ -231,7 +231,9 @@
+
+
diff --git a/src/ebpf/core/EbpfCore/EbpfCore.vcxproj.filters b/src/ebpf/core/EbpfCore/EbpfCore.vcxproj.filters
index 8b984e7f6..547b1c860 100644
--- a/src/ebpf/core/EbpfCore/EbpfCore.vcxproj.filters
+++ b/src/ebpf/core/EbpfCore/EbpfCore.vcxproj.filters
@@ -30,6 +30,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
diff --git a/src/ebpf/core/EbpfCore/ebpf_drv.c b/src/ebpf/core/EbpfCore/ebpf_drv.c
index cb8710c4c..67b21b09f 100644
--- a/src/ebpf/core/EbpfCore/ebpf_drv.c
+++ b/src/ebpf/core/EbpfCore/ebpf_drv.c
@@ -24,9 +24,10 @@ Environment:
#pragma warning(pop)
#include
-
+#include
#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:
diff --git a/src/ebpf/core/EbpfCore/ebpf_l2_hook.c b/src/ebpf/core/EbpfCore/ebpf_l2_hook.c
index d2210b27e..5ec0d52d3 100644
--- a/src/ebpf/core/EbpfCore/ebpf_l2_hook.c
+++ b/src/ebpf/core/EbpfCore/ebpf_l2_hook.c
@@ -23,6 +23,7 @@ Environment:
#pragma warning(pop)
#include
+#include
#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;
}
-
\ No newline at end of file
diff --git a/src/ebpf/core/EbpfCore/ebpf_l2_hook.h b/src/ebpf/core/EbpfCore/ebpf_l2_hook.h
index abb1b513a..617ba9873 100644
--- a/src/ebpf/core/EbpfCore/ebpf_l2_hook.h
+++ b/src/ebpf/core/EbpfCore/ebpf_l2_hook.h
@@ -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;
diff --git a/src/ebpf/core/EbpfCore/types.h b/src/ebpf/core/EbpfCore/types.h
new file mode 100644
index 000000000..60c5c882d
--- /dev/null
+++ b/src/ebpf/core/EbpfCore/types.h
@@ -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;
\ No newline at end of file
diff --git a/src/ebpf/core/EbpfTool/EbpfTool.c b/src/ebpf/core/EbpfTool/EbpfTool.c
index 7c8bc165b..87c0d5a5c 100644
--- a/src/ebpf/core/EbpfTool/EbpfTool.c
+++ b/src/ebpf/core/EbpfTool/EbpfTool.c
@@ -4,6 +4,8 @@
#include
#include
#include
+#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 \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 :
- 0: 89 4c 24 08 movl %ecx, 8(%rsp)
- 4: 83 7c 24 08 11 cmpl $17, 8(%rsp)
- 9: 75 06 jne 0x11
- b: 33 c0 xorl %eax, %eax
- d: eb 07 jmp 0x16
- f: eb 05 jmp 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
+ 10: 48 8d 50 08 leaq 8(%rax), %rdx
+ 14: 48 39 ca cmpq %rcx, %rdx
+ 17: 77 14 ja 0x2d
+ 19: 80 78 09 11 cmpb $17, 9(%rax)
+ 1d: 75 0e jne 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;
}
\ No newline at end of file
diff --git a/src/ebpf/core/EbpfTool/EbpfTool.vcxproj b/src/ebpf/core/EbpfTool/EbpfTool.vcxproj
index 6c2068249..0dd489ac9 100644
--- a/src/ebpf/core/EbpfTool/EbpfTool.vcxproj
+++ b/src/ebpf/core/EbpfTool/EbpfTool.vcxproj
@@ -118,6 +118,7 @@
_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
MultiThreadedDebug
+ $(SolutionDir)..\api\;%(AdditionalIncludeDirectories)
Console
@@ -132,6 +133,7 @@
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
+ $(SolutionDir)..\api\;%(AdditionalIncludeDirectories)
Console
@@ -143,6 +145,10 @@
+
+
+
+
diff --git a/src/ebpf/core/EbpfTool/EbpfTool.vcxproj.filters b/src/ebpf/core/EbpfTool/EbpfTool.vcxproj.filters
index 72b8a1ec2..dff0b8936 100644
--- a/src/ebpf/core/EbpfTool/EbpfTool.vcxproj.filters
+++ b/src/ebpf/core/EbpfTool/EbpfTool.vcxproj.filters
@@ -19,4 +19,12 @@
Source Files
+
+
+ Header Files
+
+
+ Header Files
+
+
\ No newline at end of file
diff --git a/src/ebpf/core/EbpfTool/droppacket.c b/src/ebpf/core/EbpfTool/droppacket.c
new file mode 100644
index 000000000..06444da76
--- /dev/null
+++ b/src/ebpf/core/EbpfTool/droppacket.c
@@ -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;
+}
\ No newline at end of file
diff --git a/src/ebpf/libs/api/protocol.h b/src/ebpf/libs/api/protocol.h
index 891d84b86..fb75334b6 100644
--- a/src/ebpf/libs/api/protocol.h
+++ b/src/ebpf/libs/api/protocol.h
@@ -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;