From e4effcc932c115138c06cdb9d14366ffd980882c Mon Sep 17 00:00:00 2001 From: Anurag Saxena Date: Sat, 9 Dec 2023 10:49:35 -0800 Subject: [PATCH 1/5] add context create/delete functions --- src/xdp/program.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/src/xdp/program.c b/src/xdp/program.c index ce04633a..39006843 100644 --- a/src/xdp/program.c +++ b/src/xdp/program.c @@ -11,10 +11,163 @@ #include "programinspect.h" #include "program.tmh" +typedef struct _EBPF_PROG_TEST_RUN_CONTEXT { + char* Data; + SIZE_T DataSize; +} EBPF_PROG_TEST_RUN_CONTEXT; + typedef struct _EBPF_XDP_MD { xdp_md_t Base; + EBPF_PROG_TEST_RUN_CONTEXT* ProgTestRunContext; } EBPF_XDP_MD; +// +// Routines for BPF_PROG_TEST_RUN. +// + +/** + * @brief Build a EBPF_XDP_MD Context for the eBPF program. This includes copying the packet data and + * metadata into a contiguous buffer and building an MDL chain for the same. + * + * @param[in] DataIn The packet data. + * @param[in] DataSizeIn The size of the packet data. + * @param[in] context_in The Context. + * @param[in] ContextSizeIn The size of the Context. + * @param[out] Context The Context to be passed to the eBPF program. + * @retval STATUS_SUCCESS The operation was successful. + * @retval STATUS_INVALID_PARAMETER One or more parameters are incorrect. + * @retval STATUS_NO_MEMORY Failed to allocate resources for this operation. + */ +static ebpf_result_t +XdpCreateContext( + _In_reads_bytes_opt_(DataSizeIn) const uint8_t* DataIn, + size_t DataSizeIn, + _In_reads_bytes_opt_(ContextSizeIn) const uint8_t* context_in, + size_t ContextSizeIn, + _Outptr_ void** Context) +{ + ebpf_result_t EbpfResult; + EBPF_XDP_MD* XdpMd = NULL; + + *Context = NULL; + + // Data is mandatory. Context is optional. + if (DataIn == NULL || DataSizeIn == 0) { + EbpfResult = EBPF_INVALID_ARGUMENT; + goto Exit; + } + + // Allocate XdpMd struct. + XdpMd = (EBPF_XDP_MD*)ExAllocatePoolZero(NonPagedPoolNx, sizeof(EBPF_XDP_MD), XDP_POOLTAG_PROGRAM); + if (XdpMd == NULL) { + EbpfResult = EBPF_NO_MEMORY; + goto Exit; + } + + // Allocate memory for ProgTestRunContext + XdpMd->ProgTestRunContext = (EBPF_PROG_TEST_RUN_CONTEXT*)ExAllocatePoolZero( + NonPagedPoolNx, sizeof(EBPF_PROG_TEST_RUN_CONTEXT), XDP_POOLTAG_PROGRAM); + if (XdpMd->ProgTestRunContext == NULL) { + EbpfResult = EBPF_NO_MEMORY; + goto Exit; + } + + // Allocate buffer for data. + XdpMd->ProgTestRunContext->Data = (char*)ExAllocatePoolZero(NonPagedPoolNx, DataSizeIn, XDP_POOLTAG_PROGRAM); + if (XdpMd->ProgTestRunContext->Data == NULL) { + EbpfResult = EBPF_NO_MEMORY; + goto Exit; + } + memcpy(XdpMd->ProgTestRunContext->Data, DataIn, DataSizeIn); + XdpMd->ProgTestRunContext->DataSize = DataSizeIn; + + XdpMd->Base.data = (void*)XdpMd->ProgTestRunContext->Data; + XdpMd->Base.data_end = (void*)(XdpMd->ProgTestRunContext->Data + XdpMd->ProgTestRunContext->DataSize); + + if (context_in != NULL && ContextSizeIn >= sizeof(xdp_md_t)) { + xdp_md_t* xdp_context = (xdp_md_t*)context_in; + XdpMd->Base.data_meta = xdp_context->data_meta; + XdpMd->Base.ingress_ifindex = xdp_context->ingress_ifindex; + } + + *Context = XdpMd; + XdpMd = NULL; + + EbpfResult = EBPF_SUCCESS; + +Exit: + if (XdpMd != NULL) { + if (XdpMd->ProgTestRunContext != NULL) { + if (XdpMd->ProgTestRunContext->Data != NULL) { + ExFreePool(XdpMd->ProgTestRunContext->Data); + } + ExFreePool(XdpMd->ProgTestRunContext); + } + ExFreePool(XdpMd); + } + + return EbpfResult; +} + +static void +XdpDeleteContext( + _In_opt_ void* Context, + _Out_writes_bytes_to_(*DataSizeOut, *DataSizeOut) uint8_t* DataOut, + _Inout_ size_t* DataSizeOut, + _Out_writes_bytes_to_(*ContextSizeOut, *ContextSizeOut) uint8_t* ContextOut, + _Inout_ size_t* ContextSizeOut) +{ + EBPF_XDP_MD* XdpMd = NULL; + + if (!Context) { + goto Exit; + } + + XdpMd = (EBPF_XDP_MD*)Context; + + // Copy the packet data to the output buffer. + if (DataOut != NULL && DataSizeOut != NULL && XdpMd->Base.data != NULL) { + size_t DataSize = *DataSizeOut; + size_t XdpDataSize = (char*)(XdpMd->Base.data_end) - (char*)(XdpMd->Base.data); + if (DataSize > XdpDataSize) { + DataSize = XdpDataSize; + } + memcpy(DataOut, XdpMd->Base.data, DataSize); + *DataSizeOut = DataSize; + } else { + *DataSizeOut = 0; + } + + // Copy some fields from the Context to the output buffer. + if (ContextOut != NULL && ContextSizeOut != NULL) { + size_t context_size = *ContextSizeOut; + if (context_size > sizeof(xdp_md_t)) { + context_size = sizeof(xdp_md_t); + } + + xdp_md_t* XdpContextOut = (xdp_md_t*)ContextOut; + XdpContextOut->data_meta = XdpMd->Base.data_meta; + XdpContextOut->ingress_ifindex = XdpMd->Base.ingress_ifindex; + *ContextSizeOut = context_size; + } else { + *ContextSizeOut = 0; + } + + if (XdpMd->ProgTestRunContext != NULL) { + if (XdpMd->ProgTestRunContext->Data != NULL) { + ExFreePool(XdpMd->ProgTestRunContext->Data); + XdpMd->ProgTestRunContext->Data = NULL; + } + ExFreePool(XdpMd->ProgTestRunContext); + XdpMd->ProgTestRunContext = NULL; + } + + ExFreePool(XdpMd); + +Exit: + return; +} + // // Data path routines. // @@ -509,6 +662,8 @@ static const ebpf_helper_function_addresses_t XdpHelperFunctionAddresses = { static const ebpf_program_data_t EbpfXdpProgramData = { .program_info = &EbpfXdpProgramInfo, .program_type_specific_helper_function_addresses = &XdpHelperFunctionAddresses, + .context_create = XdpCreateContext, + .context_destroy = XdpDeleteContext, .required_irql = DISPATCH_LEVEL, }; From b2094eb272fdf8dde384f8c0fb6468ad4cd8c074 Mon Sep 17 00:00:00 2001 From: Anurag Saxena Date: Wed, 13 Dec 2023 08:11:41 -0800 Subject: [PATCH 2/5] Add test --- test/functional/lib/tests.cpp | 44 ++++++++++++++++++++++++++++++++++ test/functional/lib/tests.h | 3 +++ test/functional/taef/tests.cpp | 4 ++++ 3 files changed, 51 insertions(+) diff --git a/test/functional/lib/tests.cpp b/test/functional/lib/tests.cpp index 81e643f5..9293ca88 100644 --- a/test/functional/lib/tests.cpp +++ b/test/functional/lib/tests.cpp @@ -58,6 +58,7 @@ #include #include +#include "ebpf_nethooks.h" #include "xdptest.h" #include "tests.h" #include "util.h" @@ -4633,6 +4634,49 @@ GenericRxEbpfPayload() LwfRxFlush(FnLwf); } +VOID +ProgTestRunRxEbpfPayload() +{ + auto If = FnMpIf; + wil::unique_handle GenericMp; + wil::unique_handle FnLwf; + UINT16 LocalPort = 0, RemotePort = 0; + ETHERNET_ADDRESS LocalHw = {}, RemoteHw = {}; + INET_ADDR LocalIp = {}, RemoteIp = {}; + const UINT32 Backfill = 13; + const UINT32 Trailer = 17; + const UCHAR UdpPayload[] = "ProgTestRunRxEbpfPayload"; + bpf_test_run_opts Opts = {}; + + unique_bpf_object BpfObject = AttachEbpfXdpProgram(If, "\\bpf\\allow_ipv6.o", "allow_ipv6"); + fd_t ProgFd = bpf_program__fd(bpf_object__find_program_by_name(BpfObject.get(), "allow_ipv6")); + + GenericMp = MpOpenGeneric(If.GetIfIndex()); + FnLwf = LwfOpenDefault(If.GetIfIndex()); + + UCHAR UdpFrame[Backfill + UDP_HEADER_STORAGE + sizeof(UdpPayload) + Trailer]; + UCHAR UdpFrameOut[Backfill + UDP_HEADER_STORAGE + sizeof(UdpPayload) + Trailer]; + UINT32 UdpFrameLength = sizeof(UdpFrame) - Backfill - Trailer; + TEST_TRUE( + PktBuildUdpFrame( + UdpFrame + Backfill, &UdpFrameLength, UdpPayload, sizeof(UdpPayload), &LocalHw, + &RemoteHw, AF_INET6, &LocalIp, &RemoteIp, LocalPort, RemotePort)); + + Opts.data_in = UdpFrame; + Opts.data_size_in = sizeof(UdpFrame); + Opts.data_out = UdpFrameOut; + Opts.data_size_out = sizeof(UdpFrameOut); + Opts.ctx_in = nullptr; + Opts.ctx_size_in = 0; + Opts.ctx_out = nullptr; + Opts.ctx_size_out = 0; + + TEST_EQUAL(0, bpf_prog_test_run_opts(ProgFd, &Opts)); + TEST_EQUAL(Opts.retval, XDP_PASS); + + TEST_EQUAL(memcmp(UdpFrame, UdpFrameOut, sizeof(UdpFrame)), 0); +} + VOID GenericRxEbpfFragments() { diff --git a/test/functional/lib/tests.h b/test/functional/lib/tests.h index 8a520c3e..c5c7221b 100644 --- a/test/functional/lib/tests.h +++ b/test/functional/lib/tests.h @@ -118,6 +118,9 @@ GenericRxEbpfTx(); VOID GenericRxEbpfPayload(); +VOID +ProgTestRunRxEbpfPayload(); + VOID GenericRxEbpfFragments(); diff --git a/test/functional/taef/tests.cpp b/test/functional/taef/tests.cpp index 142020b2..9bf7392c 100644 --- a/test/functional/taef/tests.cpp +++ b/test/functional/taef/tests.cpp @@ -420,6 +420,10 @@ TEST_CLASS(xdpfunctionaltests) ::GenericRxEbpfPayload(); } + TEST_METHOD(ProgTestRunRxEbpfPayload) { + ::ProgTestRunRxEbpfPayload(); + } + TEST_METHOD(GenericRxEbpfFragments) { ::GenericRxEbpfFragments(); } From 0040fa74a8e2b3cb346e14a485b6540391f3acda Mon Sep 17 00:00:00 2001 From: Anurag Saxena Date: Thu, 21 Dec 2023 11:56:07 -0800 Subject: [PATCH 3/5] fix --- test/functional/lib/tests.cpp | 51 +++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/test/functional/lib/tests.cpp b/test/functional/lib/tests.cpp index be784edc..ff5065ee 100644 --- a/test/functional/lib/tests.cpp +++ b/test/functional/lib/tests.cpp @@ -4652,34 +4652,28 @@ VOID ProgTestRunRxEbpfPayload() { auto If = FnMpIf; - wil::unique_handle GenericMp; - wil::unique_handle FnLwf; UINT16 LocalPort = 0, RemotePort = 0; ETHERNET_ADDRESS LocalHw = {}, RemoteHw = {}; INET_ADDR LocalIp = {}, RemoteIp = {}; - const UINT32 Backfill = 13; - const UINT32 Trailer = 17; const UCHAR UdpPayload[] = "ProgTestRunRxEbpfPayload"; bpf_test_run_opts Opts = {}; - unique_bpf_object BpfObject = AttachEbpfXdpProgram(If, "\\bpf\\allow_ipv6.o", "allow_ipv6"); + unique_bpf_object BpfObject = AttachEbpfXdpProgram(If, "\\bpf\\allow_ipv6.sys", "allow_ipv6"); fd_t ProgFd = bpf_program__fd(bpf_object__find_program_by_name(BpfObject.get(), "allow_ipv6")); - GenericMp = MpOpenGeneric(If.GetIfIndex()); - FnLwf = LwfOpenDefault(If.GetIfIndex()); - - UCHAR UdpFrame[Backfill + UDP_HEADER_STORAGE + sizeof(UdpPayload) + Trailer]; - UCHAR UdpFrameOut[Backfill + UDP_HEADER_STORAGE + sizeof(UdpPayload) + Trailer]; - UINT32 UdpFrameLength = sizeof(UdpFrame) - Backfill - Trailer; + // Build a v6 packet and verify it is allowed. + UCHAR UdpFrameV6[UDP_HEADER_STORAGE + sizeof(UdpPayload)]; + UCHAR UdpFrameOutV6[UDP_HEADER_STORAGE + sizeof(UdpPayload)]; + UINT32 UdpFrameLength = sizeof(UdpFrameV6); TEST_TRUE( PktBuildUdpFrame( - UdpFrame + Backfill, &UdpFrameLength, UdpPayload, sizeof(UdpPayload), &LocalHw, + UdpFrameV6, &UdpFrameLength, UdpPayload, sizeof(UdpPayload), &LocalHw, &RemoteHw, AF_INET6, &LocalIp, &RemoteIp, LocalPort, RemotePort)); - Opts.data_in = UdpFrame; - Opts.data_size_in = sizeof(UdpFrame); - Opts.data_out = UdpFrameOut; - Opts.data_size_out = sizeof(UdpFrameOut); + Opts.data_in = UdpFrameV6; + Opts.data_size_in = sizeof(UdpFrameV6); + Opts.data_out = UdpFrameOutV6; + Opts.data_size_out = sizeof(UdpFrameOutV6); Opts.ctx_in = nullptr; Opts.ctx_size_in = 0; Opts.ctx_out = nullptr; @@ -4688,7 +4682,30 @@ ProgTestRunRxEbpfPayload() TEST_EQUAL(0, bpf_prog_test_run_opts(ProgFd, &Opts)); TEST_EQUAL(Opts.retval, XDP_PASS); - TEST_EQUAL(memcmp(UdpFrame, UdpFrameOut, sizeof(UdpFrame)), 0); + TEST_EQUAL(memcmp(UdpFrameV6, UdpFrameOutV6, sizeof(UdpFrameV6)), 0); + + // Build a v4 packet and verify it is dropped. + UCHAR UdpFrameV4[UDP_HEADER_STORAGE + sizeof(UdpPayload)]; + UCHAR UdpFrameOutV4[UDP_HEADER_STORAGE + sizeof(UdpPayload)]; + UdpFrameLength = sizeof(UdpFrameV4); + TEST_TRUE( + PktBuildUdpFrame( + UdpFrameV4, &UdpFrameLength, UdpPayload, sizeof(UdpPayload), &LocalHw, + &RemoteHw, AF_INET, &LocalIp, &RemoteIp, LocalPort, RemotePort)); + + Opts.data_in = UdpFrameV4; + Opts.data_size_in = sizeof(UdpFrameV4); + Opts.data_out = UdpFrameOutV4; + Opts.data_size_out = sizeof(UdpFrameOutV4); + Opts.ctx_in = nullptr; + Opts.ctx_size_in = 0; + Opts.ctx_out = nullptr; + Opts.ctx_size_out = 0; + + TEST_EQUAL(0, bpf_prog_test_run_opts(ProgFd, &Opts)); + TEST_EQUAL(Opts.retval, XDP_DROP); + + TEST_EQUAL(memcmp(UdpFrameV4, UdpFrameOutV4, sizeof(UdpFrameV4)), 0); } VOID From 590c9908481a8f4f1ebc1ea04ec0e9aebe03b467 Mon Sep 17 00:00:00 2001 From: Anurag Saxena Date: Tue, 26 Dec 2023 19:52:12 -0800 Subject: [PATCH 4/5] cr comments --- src/xdp/program.c | 58 +++++++++++++++++++++++++++++++---------------- src/xdp/xdpp.h | 1 + 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/xdp/program.c b/src/xdp/program.c index 39006843..dde39039 100644 --- a/src/xdp/program.c +++ b/src/xdp/program.c @@ -21,10 +21,36 @@ typedef struct _EBPF_XDP_MD { EBPF_PROG_TEST_RUN_CONTEXT* ProgTestRunContext; } EBPF_XDP_MD; +static __forceinline NTSTATUS EbpfResultToNtStatus(ebpf_result_t Result) +{ + switch (Result) { + case EBPF_SUCCESS: + return STATUS_SUCCESS; + case EBPF_INVALID_ARGUMENT: + return STATUS_INVALID_PARAMETER; + case EBPF_NO_MEMORY: + return STATUS_NO_MEMORY; + default: + return STATUS_UNSUCCESSFUL; + } +} + // // Routines for BPF_PROG_TEST_RUN. // +static void EbpfProgramTestRunContextFree(_In_opt_ _Post_invalid_ EBPF_PROG_TEST_RUN_CONTEXT* Context) +{ + if (Context == NULL) { + return; + } + + if (Context->Data != NULL) { + ExFreePool(Context->Data); + } + ExFreePool(Context); +} + /** * @brief Build a EBPF_XDP_MD Context for the eBPF program. This includes copying the packet data and * metadata into a contiguous buffer and building an MDL chain for the same. @@ -46,9 +72,12 @@ XdpCreateContext( size_t ContextSizeIn, _Outptr_ void** Context) { + NTSTATUS Status; ebpf_result_t EbpfResult; EBPF_XDP_MD* XdpMd = NULL; + TraceEnter(TRACE_CORE, "Create program context, DataIn=%p, DataSizeIn=%llu", DataIn, DataSizeIn); + *Context = NULL; // Data is mandatory. Context is optional. @@ -58,7 +87,7 @@ XdpCreateContext( } // Allocate XdpMd struct. - XdpMd = (EBPF_XDP_MD*)ExAllocatePoolZero(NonPagedPoolNx, sizeof(EBPF_XDP_MD), XDP_POOLTAG_PROGRAM); + XdpMd = (EBPF_XDP_MD*)ExAllocatePoolZero(NonPagedPoolNx, sizeof(EBPF_XDP_MD), XDP_POOLTAG_PROGRAM_CONTEXT); if (XdpMd == NULL) { EbpfResult = EBPF_NO_MEMORY; goto Exit; @@ -66,14 +95,14 @@ XdpCreateContext( // Allocate memory for ProgTestRunContext XdpMd->ProgTestRunContext = (EBPF_PROG_TEST_RUN_CONTEXT*)ExAllocatePoolZero( - NonPagedPoolNx, sizeof(EBPF_PROG_TEST_RUN_CONTEXT), XDP_POOLTAG_PROGRAM); + NonPagedPoolNx, sizeof(EBPF_PROG_TEST_RUN_CONTEXT), XDP_POOLTAG_PROGRAM_CONTEXT); if (XdpMd->ProgTestRunContext == NULL) { EbpfResult = EBPF_NO_MEMORY; goto Exit; } // Allocate buffer for data. - XdpMd->ProgTestRunContext->Data = (char*)ExAllocatePoolZero(NonPagedPoolNx, DataSizeIn, XDP_POOLTAG_PROGRAM); + XdpMd->ProgTestRunContext->Data = (char*)ExAllocatePoolZero(NonPagedPoolNx, DataSizeIn, XDP_POOLTAG_PROGRAM_CONTEXT); if (XdpMd->ProgTestRunContext->Data == NULL) { EbpfResult = EBPF_NO_MEMORY; goto Exit; @@ -97,15 +126,14 @@ XdpCreateContext( Exit: if (XdpMd != NULL) { - if (XdpMd->ProgTestRunContext != NULL) { - if (XdpMd->ProgTestRunContext->Data != NULL) { - ExFreePool(XdpMd->ProgTestRunContext->Data); - } - ExFreePool(XdpMd->ProgTestRunContext); - } + EbpfProgramTestRunContextFree(XdpMd->ProgTestRunContext); ExFreePool(XdpMd); } + Status = EbpfResultToNtStatus(EbpfResult); + + TraceExitStatus(TRACE_CORE); + return EbpfResult; } @@ -119,7 +147,7 @@ XdpDeleteContext( { EBPF_XDP_MD* XdpMd = NULL; - if (!Context) { + if (Context == NULL) { goto Exit; } @@ -153,15 +181,7 @@ XdpDeleteContext( *ContextSizeOut = 0; } - if (XdpMd->ProgTestRunContext != NULL) { - if (XdpMd->ProgTestRunContext->Data != NULL) { - ExFreePool(XdpMd->ProgTestRunContext->Data); - XdpMd->ProgTestRunContext->Data = NULL; - } - ExFreePool(XdpMd->ProgTestRunContext); - XdpMd->ProgTestRunContext = NULL; - } - + EbpfProgramTestRunContextFree(XdpMd->ProgTestRunContext); ExFreePool(XdpMd); Exit: diff --git a/src/xdp/xdpp.h b/src/xdp/xdpp.h index 116127ba..d2792d1b 100644 --- a/src/xdp/xdpp.h +++ b/src/xdp/xdpp.h @@ -31,3 +31,4 @@ #define XDP_POOLTAG_RING 'rpdX' // Xdpr #define XDP_POOLTAG_RXQUEUE 'RpdX' // XdpR #define XDP_POOLTAG_TXQUEUE 'TpdX' // XdpT +#define XDP_POOLTAG_PROGRAM_CONTEXT 'cpdX' // Xdpc From 7b195aa1d4d95ee9458cc1518dbc0dd6c7ac59bb Mon Sep 17 00:00:00 2001 From: Anurag Saxena Date: Sun, 14 Jan 2024 09:25:40 -0800 Subject: [PATCH 5/5] cr comments --- src/xdp/program.c | 4 +- test/spinxsk/spinxsk.c | 150 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 151 insertions(+), 3 deletions(-) diff --git a/src/xdp/program.c b/src/xdp/program.c index dde39039..9f1a5bde 100644 --- a/src/xdp/program.c +++ b/src/xdp/program.c @@ -147,6 +147,8 @@ XdpDeleteContext( { EBPF_XDP_MD* XdpMd = NULL; + TraceEnter(TRACE_CORE, "Delete program context, Context=%p", Context); + if (Context == NULL) { goto Exit; } @@ -185,7 +187,7 @@ XdpDeleteContext( ExFreePool(XdpMd); Exit: - return; + TraceExitSuccess(TRACE_CORE); } // diff --git a/test/spinxsk/spinxsk.c b/test/spinxsk/spinxsk.c index aa07b79a..5078bff7 100644 --- a/test/spinxsk/spinxsk.c +++ b/test/spinxsk/spinxsk.c @@ -378,6 +378,149 @@ FuzzHookId( } } +HRESULT +FuzzProgTestRunXdpEbpfProgram() +{ + HRESULT Result; + CHAR Path[MAX_PATH]; + const CHAR *ProgramRelativePath = NULL; + struct bpf_object *BpfObject = NULL; + struct bpf_program *BpfProgram = NULL; + int ProgramFd; + int OriginalThreadPriority; + int PacketInSize = 100; + UCHAR* PacketIn = NULL; + int PacketOutSize = 100; + UCHAR* PacketOut = NULL; + struct bpf_test_run_opts Opts = {0}; + + if (!enableEbpf) { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + OriginalThreadPriority = GetThreadPriority(GetCurrentThread()); + ASSERT_FRE(OriginalThreadPriority != THREAD_PRIORITY_ERROR_RETURN); + + Result = GetCurrentBinaryPath(Path, sizeof(Path)); + if (FAILED(Result)) { + goto Exit; + } + + ProgramRelativePath = "\\bpf\\allow_ipv6.sys"; + + ASSERT_FRE(strcat_s(Path, sizeof(Path), ProgramRelativePath) == 0); + + // + // To work around control path delays caused by eBPF's epoch implementation, + // boost this thread's priority when invoking eBPF APIs. + // + ASSERT_FRE(SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)); + + TraceVerbose("bpf_object__open(%s)", Path); + BpfObject = bpf_object__open(Path); + if (BpfObject == NULL) { + TraceVerbose("bpf_object__open(%s) failed: %d", Path, errno); + Result = E_FAIL; + goto Exit; + } + + TraceVerbose("bpf_object__next_program(%p, %p)", BpfObject, NULL); + BpfProgram = bpf_object__next_program(BpfObject, NULL); + if (BpfProgram == NULL) { + TraceVerbose("bpf_object__next_program failed: %d", errno); + Result = E_FAIL; + goto Exit; + } + + TraceVerbose("bpf_object__load(%p)", BpfObject); + if (bpf_object__load(BpfObject) < 0) { + TraceVerbose("bpf_object__load failed: %d", errno); + Result = E_FAIL; + goto Exit; + } + + TraceVerbose("bpf_program__fd(%p)", BpfProgram); + ProgramFd = bpf_program__fd(BpfProgram); + if (ProgramFd < 0) { + TraceVerbose("bpf_program__fd failed: %d", errno); + Result = E_FAIL; + goto Exit; + } + + switch (RandUlong() % 3) { + case 0: + PacketInSize = 0; + break; + case 1: + PacketInSize /= 2; + break; + case 2: + PacketInSize *= 2; + break; + } + + if (PacketInSize > 0) { + PacketIn = malloc(PacketInSize); + if (PacketIn == NULL) { + Result = E_OUTOFMEMORY; + goto Exit; + } + memset(PacketIn, 0, PacketInSize); + } + + switch (RandUlong() % 3) { + case 0: + PacketOutSize = 0; + break; + case 1: + PacketOutSize /= 2; + break; + case 2: + PacketOutSize *= 2; + break; + } + + if (PacketOutSize > 0) { + PacketOut = malloc(PacketOutSize); + if (PacketOut == NULL) { + Result = E_OUTOFMEMORY; + goto Exit; + } + memset(PacketOut, 0, PacketOutSize); + } + + Opts.data_in = PacketIn; + Opts.data_size_in = PacketInSize; + Opts.data_out = PacketOut; + Opts.data_size_out = PacketOutSize; + Opts.ctx_in = NULL; + Opts.ctx_size_in = 0; + Opts.ctx_out = NULL; + Opts.ctx_size_out = 0; + + // Don't care about the return value here. + bpf_prog_test_run_opts(ProgramFd, &Opts); + +Exit: + + // There is no other use of the loaded program. Unload before exiting. + if (BpfObject != NULL) { + TraceVerbose("bpf_object__close(%p)", BpfObject); + bpf_object__close(BpfObject); + } + + ASSERT_FRE(SetThreadPriority(GetCurrentThread(), OriginalThreadPriority)); + + if (PacketIn != NULL) { + free(PacketIn); + } + if (PacketOut != NULL) { + free(PacketOut); + } + + return Result; +} + HRESULT AttachXdpEbpfProgram( _In_ QUEUE_CONTEXT *Queue, @@ -420,13 +563,13 @@ AttachXdpEbpfProgram( switch (RandUlong() % 3) { case 0: - ProgramRelativePath = "\\bpf\\drop.o"; + ProgramRelativePath = "\\bpf\\drop.sys"; break; case 1: ProgramRelativePath = "\\bpf\\pass.sys"; break; case 2: - ProgramRelativePath = "\\bpf\\l1fwd.o"; + ProgramRelativePath = "\\bpf\\l1fwd.sys"; break; default: ASSERT_FRE(FALSE); @@ -1940,6 +2083,9 @@ XskFuzzerWorkerFn( queue, queue->sharedUmemSock, queue->sock); } + // Fuzz prog_test_run. + FuzzProgTestRunXdpEbpfProgram(); + FuzzInterface(fuzzer, queue); FuzzSocketRxTxSetup(