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;