From b375fbc68557cc162c57761d6d1986cdf77f5a57 Mon Sep 17 00:00:00 2001 From: Laksh Date: Fri, 1 Nov 2024 10:41:32 -0700 Subject: [PATCH] Fix netevent prog test (#145) * added prog test run to context * Revert "added prog test run to context" This reverts commit 9665259d0543664a9aad92a32638e539ea415f05. * fix context_create/destroy * added unit test * data_out fix * add sleep for event_map read * added negative test * review changes * added ctx_out --------- Co-authored-by: Laksh Kotian Co-authored-by: Sharmi --- .../neteventebpfext/netevent_ebpf_ext_event.c | 18 ++-- .../netevent_ebpfext_unit.cpp | 96 +++++++++++++++++++ 2 files changed, 105 insertions(+), 9 deletions(-) diff --git a/ebpf_extensions/neteventebpfext/netevent_ebpf_ext_event.c b/ebpf_extensions/neteventebpfext/netevent_ebpf_ext_event.c index 29634c5f..9a54a276 100644 --- a/ebpf_extensions/neteventebpfext/netevent_ebpf_ext_event.c +++ b/ebpf_extensions/neteventebpfext/netevent_ebpf_ext_event.c @@ -403,7 +403,7 @@ _ebpf_netevent_program_context_create( // Copy the event's pointer & size from the caller, to the out context. netevent_event_context->netevent_event_md.event_data_start = (uint8_t*)data_in; netevent_event_context->netevent_event_md.event_data_end = (uint8_t*)data_in + data_size_in; - *context = netevent_event_context; + *context = &netevent_event_context->netevent_event_md; netevent_event_context = NULL; result = EBPF_SUCCESS; @@ -424,18 +424,19 @@ _ebpf_netevent_program_context_destroy( _Inout_ size_t* context_size_out) { EBPF_EXT_LOG_ENTRY(); + netevent_event_notify_context_t* netevent_event_context = NULL; + netevent_event_md_t* netevent_event_context_out = NULL; - netevent_event_notify_context_t* netevent_event_context = (netevent_event_notify_context_t*)context; - netevent_event_md_t* netevent_event_context_out = (netevent_event_md_t*)context_out; - - if (!netevent_event_context) { + if (!context) { goto Exit; } + netevent_event_context = CONTAINING_RECORD(context, netevent_event_notify_context_t, netevent_event_md); + netevent_event_context_out = (netevent_event_md_t*)context_out; + if (context_out != NULL && *context_size_out >= sizeof(netevent_event_md_t)) { // Copy the context to the caller. memcpy(netevent_event_context_out, &netevent_event_context->netevent_event_md, sizeof(netevent_event_md_t)); - *context_size_out = sizeof(netevent_event_md_t); // Zero out the event context info. netevent_event_context_out->event_data_start = 0; @@ -446,9 +447,8 @@ _ebpf_netevent_program_context_destroy( } // Copy the event data to 'data_out'. - if (data_out != NULL && *data_size_out >= (size_t)( - netevent_event_context->netevent_event_md.event_data_end - - netevent_event_context->netevent_event_md.event_data_start)) { + if (data_out != NULL && *data_size_out >= (size_t)(netevent_event_context->netevent_event_md.event_data_end - + netevent_event_context->netevent_event_md.event_data_start)) { memcpy( data_out, netevent_event_context->netevent_event_md.event_data_start, diff --git a/tests/neteventebpfext/neteventebpfext_unit/netevent_ebpfext_unit.cpp b/tests/neteventebpfext/neteventebpfext_unit/netevent_ebpfext_unit.cpp index 0c626549..90683d77 100644 --- a/tests/neteventebpfext/neteventebpfext_unit/netevent_ebpfext_unit.cpp +++ b/tests/neteventebpfext/neteventebpfext_unit/netevent_ebpfext_unit.cpp @@ -25,6 +25,7 @@ CATCH_REGISTER_LISTENER(cxplat_passed_test_log) #define MAX_EVENTS_COUNT 1000 #define NETEVENT_EVENT_TEST_TIMEOUT_SEC 90 #define NETEVENT_EVENT_STRESS_TEST_TIMEOUT_SEC 90 +#define MAX_PACKET_SIZE 1600 struct bpf_map* netevent_event_map; struct bpf_map* command_map; @@ -260,3 +261,98 @@ TEST_CASE("netevent_drivers_load_unload_stress", "[neteventebpfext]") REQUIRE(neteventebpfext_driver.stop() == true); REQUIRE(neteventebpfext_driver.unload() == true); } + +TEST_CASE("netevent_bpf_prog_run_test", "[neteventebpfext]") +{ + // The BPF object will take some time to unload from the previous test + // TODO: Remove sleep once this issue is fixed: https://github.com/microsoft/ebpf-for-windows/issues/2667 + std::this_thread::sleep_for(std::chrono::seconds(10)); + + // Load and start neteventebpfext extension driver. + driver_service neteventebpfext_driver; + REQUIRE( + neteventebpfext_driver.create( + L"neteventebpfext", driver_service::get_driver_path("neteventebpfext.sys").c_str()) == true); + REQUIRE(neteventebpfext_driver.start() == true); + + // Load the NetEventMonitor native BPF program. + struct bpf_object* object = bpf_object__open("netevent_monitor.sys"); + REQUIRE(object != nullptr); + + int res = bpf_object__load(object); + REQUIRE(res == 0); + + // Find and attach to the netevent_monitor BPF program. + bpf_program* netevent_monitor = bpf_object__find_program_by_name(object, "NetEventMonitor"); + REQUIRE(netevent_monitor != nullptr); + bpf_link* netevent_monitor_link = bpf_program__attach(netevent_monitor); + REQUIRE(netevent_monitor_link != nullptr); + + // Attach to the eBPF ring buffer event map. + bpf_map* netevent_events_map = bpf_object__find_map_by_name(object, "netevent_events_map"); + REQUIRE(netevent_events_map != nullptr); + ring_buffer* ring = + ring_buffer__new(bpf_map__fd(netevent_events_map), netevent_monitor_event_callback, nullptr, nullptr); + REQUIRE(ring != nullptr); + + // Initialize structures required for bpf_prog_test_run_opts + bpf_test_run_opts bpf_opts = {0}; + netevent_event_md_t netevent_ctx_in = {0}; + netevent_event_md_t netevent_ctx_out = {0}; + unsigned char dummy_data_in[] = {NOTIFY_EVENT_TYPE_NETEVENT, 'a', 'b'}; + const size_t dummy_data_size = sizeof(dummy_data_in); + unsigned char data_out[MAX_PACKET_SIZE] = {0}; + uint32_t event_count_before = event_count; + fd_t netevent_program_fd = bpf_program__fd(netevent_monitor); + REQUIRE(netevent_program_fd != ebpf_fd_invalid); + + // Prepare bpf_opts + bpf_opts.repeat = 1; + bpf_opts.ctx_in = &netevent_ctx_in; + bpf_opts.ctx_size_in = sizeof(netevent_ctx_in); + bpf_opts.ctx_out = &netevent_ctx_out; + bpf_opts.ctx_size_out = sizeof(netevent_ctx_out); + bpf_opts.data_in = &dummy_data_in; + bpf_opts.data_size_in = static_cast(dummy_data_size); + // Set the data_out buffer to hold the output. + bpf_opts.data_out = data_out; + bpf_opts.data_size_out = sizeof(data_out); + + // Execute the program + REQUIRE(bpf_prog_test_run_opts(netevent_program_fd, &bpf_opts) == 0); + + REQUIRE(bpf_opts.data_size_out == dummy_data_size); + REQUIRE(memcmp(dummy_data_in, data_out, dummy_data_size) == 0); + REQUIRE(bpf_opts.ctx_size_out == sizeof(netevent_ctx_out)); + std::this_thread::sleep_for(std::chrono::seconds(5)); + REQUIRE(event_count == event_count_before + 1); + + // Execute negative cases + bpf_opts.ctx_in = NULL; + bpf_opts.ctx_size_in = 0; + + REQUIRE(bpf_prog_test_run_opts(netevent_program_fd, &bpf_opts) != 0); + + // context smaller than netevent_md must be rejected + unsigned char smaller_ctx[sizeof(netevent_ctx_in) - 1]; + bpf_opts.ctx_in = &smaller_ctx; + bpf_opts.ctx_size_in = sizeof(smaller_ctx); + + REQUIRE(bpf_prog_test_run_opts(netevent_program_fd, &bpf_opts) != 0); + + // Detach the program (link) from the attach point. + int link_fd = bpf_link__fd(netevent_monitor_link); + REQUIRE(link_fd != ebpf_fd_invalid); + REQUIRE(bpf_link_detach(link_fd) == 0); + REQUIRE(bpf_link__destroy(netevent_monitor_link) == 0); + + // Free the ring buffer manager + ring_buffer__free(ring); + + // Free the BPF object. + bpf_object__close(object); + + // Stop and unload the neteventebpfext extension driver (NPI client). + REQUIRE(neteventebpfext_driver.stop() == true); + REQUIRE(neteventebpfext_driver.unload() == true); +} \ No newline at end of file