Skip to content

Commit

Permalink
Add additional netsh tests (microsoft#298)
Browse files Browse the repository at this point in the history
Fix a couple bugs that the tests uncovered
Remove duplicate "error: error:" prefix in messages on verification

Fixes microsoft#240

Signed-off-by: Dave Thaler <dthaler@ntdev.microsoft.com>

Co-authored-by: Alan Jowett <alanjo@microsoft.com>
  • Loading branch information
dthaler and Alan-Jowett authored Jun 24, 2021
1 parent b0bb089 commit 5a5dbc6
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 33 deletions.
4 changes: 4 additions & 0 deletions libs/api/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ ebpf_api_elf_verify_section(

std::ostringstream output;

*report = nullptr;
*error_message = nullptr;

try {
const ebpf_platform_t* platform = &g_ebpf_platform_windows;
ebpf_verifier_options_t verifier_options = ebpf_verifier_default_options;
Expand Down Expand Up @@ -376,6 +379,7 @@ ebpf_api_elf_verify_section(
} catch (std::exception ex) {
error << "Failed to load eBPF program from " << file;
*error_message = allocate_string(error.str());
return 1;
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion libs/ebpfnetsh/elf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ handle_ebpf_show_verification(
return NO_ERROR;
} else {
if (error_message) {
std::cerr << "error: " << error_message << std::endl;
std::cerr << error_message << std::endl;
}
if (report) {
std::cerr << "\nVerification report:\n" << report << std::endl;
Expand Down
33 changes: 1 addition & 32 deletions tests/end_to_end/end_to_end.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@

#include "catch2\catch.hpp"
#include "common_tests.h"
#include "ebpf_api.h"
#include "ebpf_bind_program_data.h"
#include "ebpf_core.h"
#include "ebpf_xdp_program_data.h"
#include "helpers.h"
#include "mock.h"
#include "test_helper.hpp"
#include "tlv.h"
namespace ebpf {
#pragma warning(push)
Expand Down Expand Up @@ -149,36 +148,6 @@ prepare_udp_packet(uint16_t udp_length)
return packet;
}

class _test_helper_end_to_end
{
public:
_test_helper_end_to_end()
{
device_io_control_handler = GlueDeviceIoControl;
create_file_handler = GlueCreateFileW;
close_handle_handler = GlueCloseHandle;
REQUIRE(ebpf_core_initiate() == EBPF_SUCCESS);
ec_initialized = true;
REQUIRE(ebpf_api_initiate() == EBPF_SUCCESS);
api_initialized = true;
}
~_test_helper_end_to_end()
{
if (api_initialized)
ebpf_api_terminate();
if (ec_initialized)
ebpf_core_terminate();

device_io_control_handler = nullptr;
create_file_handler = nullptr;
close_handle_handler = nullptr;
}

private:
bool ec_initialized = false;
bool api_initialized = false;
};

#define SAMPLE_PATH ""

void
Expand Down
70 changes: 70 additions & 0 deletions tests/end_to_end/netsh_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "capture_helper.hpp"
#include "catch2\catch.hpp"
#include "elf.h"
#include "programs.h"
#include "test_helper.hpp"

#pragma region
// Mock Netsh.exe APIs.
Expand Down Expand Up @@ -59,6 +61,8 @@ static std::string
_run_netsh_command(
_In_ FN_HANDLE_CMD* command, _In_z_ const wchar_t* arg1, _In_z_ const wchar_t* arg2, _Out_ int* result)
{
_test_helper_end_to_end test_helper;

capture_helper_t capture;
errno_t error = capture.begin_capture();
if (error != NO_ERROR) {
Expand Down Expand Up @@ -161,3 +165,69 @@ TEST_CASE("show sections bpf.o xdp_prog", "[netsh][sections]")
"packet_access: 0\n"
"store : 0\n");
}

TEST_CASE("show verification nosuchfile.o", "[netsh][verification]")
{
int result;
std::string output = _run_netsh_command(handle_ebpf_show_verification, L"nosuchfile.o", nullptr, &result);
REQUIRE(result == ERROR_SUPPRESS_OUTPUT);
REQUIRE(output == "error: No such file or directory opening nosuchfile.o\n");
}

TEST_CASE("show verification bpf.o", "[netsh][verification]")
{
int result;
std::string output = _run_netsh_command(handle_ebpf_show_verification, L"bpf.o", nullptr, &result);
REQUIRE(result == NO_ERROR);
REQUIRE(
output == "\n"
"\n"
"0 errors\n"
"Verification succeeded\n"
"Program terminates within 6 instructions\n");
}

TEST_CASE("show verification droppacket.o", "[netsh][verification]")
{
int result;
std::string output = _run_netsh_command(handle_ebpf_show_verification, L"droppacket.o", L"xdp", &result);
REQUIRE(result == NO_ERROR);
REQUIRE(
output == "\n"
"\n"
"0 errors\n"
"Verification succeeded\n"
"Program terminates within 78 instructions\n");
}

TEST_CASE("show verification droppacket_unsafe.o", "[netsh][verification]")
{
int result;
std::string output = _run_netsh_command(handle_ebpf_show_verification, L"droppacket_unsafe.o", L"xdp", &result);
REQUIRE(result == ERROR_SUPPRESS_OUTPUT);
REQUIRE(
output == "Verification failed\n"
"\n"
"Verification report:\n"
"\n"
"2: r2 = *(u8 *)(r1 + 9)\n"
" Upper bound must be at most packet_size (valid_access(r1, 9:1))\n"
"4: r1 = *(u16 *)(r1 + 24)\n"
" Upper bound must be at most packet_size (valid_access(r1, 24:2))\n"
"\n"
"2 errors\n"
"\n");
}

TEST_CASE("show programs", "[netsh][programs]")
{
int result;
std::string output = _run_netsh_command(handle_ebpf_show_programs, nullptr, nullptr, &result);
REQUIRE(result == NO_ERROR);

// Since we mocked the ioctl, there should be no programs shown.
REQUIRE(
output == "\n"
" File Name Section Requested Execution Type\n"
"==================== =============== ========================\n");
}
60 changes: 60 additions & 0 deletions tests/end_to_end/test_helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#pragma once
#include "ebpf_api.h"
#include "ebpf_core.h"
#include "mock.h"

BOOL
GlueCloseHandle(ebpf_handle_t hObject);

ebpf_handle_t
GlueCreateFileW(
PCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
PSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
ebpf_handle_t hTemplateFile);

BOOL
GlueDeviceIoControl(
ebpf_handle_t hDevice,
DWORD dwIoControlCode,
PVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
PDWORD lpBytesReturned,
OVERLAPPED* lpOverlapped);

class _test_helper_end_to_end
{
public:
_test_helper_end_to_end()
{
device_io_control_handler = GlueDeviceIoControl;
create_file_handler = GlueCreateFileW;
close_handle_handler = GlueCloseHandle;
REQUIRE(ebpf_core_initiate() == EBPF_SUCCESS);
ec_initialized = true;
REQUIRE(ebpf_api_initiate() == EBPF_SUCCESS);
api_initialized = true;
}
~_test_helper_end_to_end()
{
if (api_initialized)
ebpf_api_terminate();
if (ec_initialized)
ebpf_core_terminate();

device_io_control_handler = nullptr;
create_file_handler = nullptr;
close_handle_handler = nullptr;
}

private:
bool ec_initialized = false;
bool api_initialized = false;
};
1 change: 1 addition & 0 deletions tests/unit/test.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
<ItemGroup>
<ClInclude Include="..\end_to_end\helpers.h" />
<ClInclude Include="..\end_to_end\mock.h" />
<ClInclude Include="..\end_to_end\test_helper.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
Expand Down
3 changes: 3 additions & 0 deletions tests/unit/test.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,8 @@
<ClInclude Include="..\end_to_end\mock.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\end_to_end\test_helper.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

0 comments on commit 5a5dbc6

Please sign in to comment.