From 12f73c3013e6d178d59ee111d6e81fb8e49c4622 Mon Sep 17 00:00:00 2001 From: Dhiren Vispute <86131363+dv-msft@users.noreply.github.com> Date: Mon, 26 Feb 2024 08:22:24 -0800 Subject: [PATCH] Add negative test program and test for xdp datasize check (#3292) Co-authored-by: Dhiren Vispute --- tests/end_to_end/netsh_test.cpp | 52 +++++++++++++++++++++++ tests/sample/unsafe/xdp_datasize_unsafe.c | 44 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 tests/sample/unsafe/xdp_datasize_unsafe.c diff --git a/tests/end_to_end/netsh_test.cpp b/tests/end_to_end/netsh_test.cpp index 841fd7ddaa..9edbd80d38 100644 --- a/tests/end_to_end/netsh_test.cpp +++ b/tests/end_to_end/netsh_test.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -380,6 +381,57 @@ TEST_CASE("show verification droppacket_unsafe.o", "[netsh][verification]") "\n"); } +TEST_CASE("show verification xdp_datasize_unsafe.o", "[netsh][verification]") +{ + _test_helper_netsh test_helper; + test_helper.initialize(); + + int result; + std::string output = + _run_netsh_command(handle_ebpf_show_verification, L"xdp_datasize_unsafe.o", L"xdp", nullptr, &result); + REQUIRE(result == ERROR_SUPPRESS_OUTPUT); + output = strip_paths(output); + REQUIRE( + output == "Verification failed\n" + "\n" + "Verification report:\n" + "\n" + "; ./tests/sample/unsafe/xdp_datasize_unsafe.c:32\n" + "; if (next_header + sizeof(ETHERNET_HEADER) > (char*)ctx->data_end) {\n" + "4: (r3.type in {number, ctx, stack, packet, shared})\n" + "; ./tests/sample/unsafe/xdp_datasize_unsafe.c:32\n" + "; if (next_header + sizeof(ETHERNET_HEADER) > (char*)ctx->data_end) {\n" + "5: Invalid type (valid_access(r3.offset) for comparison/subtraction)\n" + "; ./tests/sample/unsafe/xdp_datasize_unsafe.c:32\n" + "; if (next_header + sizeof(ETHERNET_HEADER) > (char*)ctx->data_end) {\n" + "5: (r3.type == non_map_fd)\n" + "; ./tests/sample/unsafe/xdp_datasize_unsafe.c:32\n" + "; if (next_header + sizeof(ETHERNET_HEADER) > (char*)ctx->data_end) {\n" + "5: Cannot subtract pointers to different regions (r3.type == r1.type in {ctx, stack, packet})\n" + "; ./tests/sample/unsafe/xdp_datasize_unsafe.c:38\n" + "; if (ethernet_header->Type != ntohs(ETHERNET_TYPE_IPV4) && ethernet_header->Type != " + "ntohs(ETHERNET_TYPE_IPV6)) {\n" + "6: (r2.type in {ctx, stack, packet, shared})\n" + "; ./tests/sample/unsafe/xdp_datasize_unsafe.c:38\n" + "; if (ethernet_header->Type != ntohs(ETHERNET_TYPE_IPV4) && ethernet_header->Type != " + "ntohs(ETHERNET_TYPE_IPV6)) {\n" + "6: Invalid type (valid_access(r2.offset+12, width=2) for read)\n" + "; ./tests/sample/unsafe/xdp_datasize_unsafe.c:38\n" + "; if (ethernet_header->Type != ntohs(ETHERNET_TYPE_IPV4) && ethernet_header->Type != " + "ntohs(ETHERNET_TYPE_IPV6)) {\n" + "7: (r1.type == number)\n" + "; ./tests/sample/unsafe/xdp_datasize_unsafe.c:38\n" + "; if (ethernet_header->Type != ntohs(ETHERNET_TYPE_IPV4) && ethernet_header->Type != " + "ntohs(ETHERNET_TYPE_IPV6)) {\n" + "8: (r1.type == number)\n" + "; ./tests/sample/unsafe/xdp_datasize_unsafe.c:43\n" + "; return rc;\n" + "10: (r0.type == number)\n" + "\n" + "9 errors\n" + "\n"); +} + TEST_CASE("show verification printk_unsafe.o", "[netsh][verification]") { _test_helper_netsh test_helper; diff --git a/tests/sample/unsafe/xdp_datasize_unsafe.c b/tests/sample/unsafe/xdp_datasize_unsafe.c new file mode 100644 index 0000000000..3841aa4ecf --- /dev/null +++ b/tests/sample/unsafe/xdp_datasize_unsafe.c @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +// clang -O2 -Werror -c xdp_datasize_unsafe.c -o xdp_datasize_unsafe_jit.o +// +// For bpf code: clang -target bpf -O2 -Werror -c xdp_datsize_unsafe.c -o xdp_datasize_unsafe.o +// + +#include "bpf_endian.h" +#include "bpf_helpers.h" +#include "net/if_ether.h" +#include "net/ip.h" +#include "net/udp.h" + +SEC("xdp") +inline void* +data_start(xdp_md_t* ctx) +{ + void* ptr; + asm volatile("%0 = *(u32 *)(%1 + %2)" : "=r"(ptr) : "r"(ctx), "i"(__builtin_offsetof(xdp_md_t, data))); + return ptr; +} + +SEC("xdp") +int +unsafe_program(xdp_md_t* ctx) +{ + int rc = XDP_PASS; + + ETHERNET_HEADER* ethernet_header = NULL; + char* next_header = data_start(ctx); // <== 64-bit truncated to 32-bit. + if (next_header + sizeof(ETHERNET_HEADER) > (char*)ctx->data_end) { + goto Done; + } + + ethernet_header = (ETHERNET_HEADER*)next_header; + next_header = (char*)(ethernet_header + 1); + if (ethernet_header->Type != ntohs(ETHERNET_TYPE_IPV4) && ethernet_header->Type != ntohs(ETHERNET_TYPE_IPV6)) { + rc = XDP_DROP; + } + +Done: + return rc; +}