Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the IOCTL numbers so that ebpfapi.dll for x64 and x64-NativeOnly are cross-compatible. #3305

Merged
merged 14 commits into from
Mar 5, 2024
18 changes: 18 additions & 0 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,24 @@ jobs:
capture_etw: true
leak_detection: true

# Run the unit tests for NativeOnly build in GitHub.
unit_tests_native_only:
# Always run this job.
needs: regular_native-only
uses: ./.github/workflows/reusable-test.yml
with:
name: unit_tests
pre_test: appverif -enable Exceptions Handles Locks Memory SRWLock Threadpool TLS DangerousAPIs DirtyStacks TimeRollOver -for unit_tests.exe
# Exclude [processes] test that CodeCoverage can't work with.
test_command: .\unit_tests.exe -d yes ~[processes]
build_artifact: Build-x64-native-only
environment: windows-2022
code_coverage: true
gather_dumps: true
capture_etw: true
leak_detection: true
configurations: '["NativeOnlyDebug", "NativeOnlyRelease"]'

# Run the netebpfext unit tests in GitHub.
netebpf_ext_unit_tests:
# Always run this job.
Expand Down
19 changes: 19 additions & 0 deletions libs/execution_context/ebpf_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2463,6 +2463,11 @@ typedef struct _ebpf_protocol_handler
EBPF_OFFSET_OF(ebpf_operation_##OPERATION##_reply_t, VARIABLE_REPLY), .flags.value = FLAGS \
}

#define DECLARE_PROTOCOL_HANDLER_INVALID(type) \
{ \
type, NULL, 0, 0, .flags.value = 0 \
}

#define ALIAS_TYPES(X, Y) \
typedef ebpf_operation_##X##_request_t ebpf_operation_##Y##_request_t; \
typedef ebpf_operation_##X##_reply_t ebpf_operation_##Y##_reply_t;
Expand All @@ -2478,13 +2483,20 @@ static ebpf_protocol_handler_t _ebpf_protocol_handlers[] = {
#if !defined(CONFIG_BPF_JIT_DISABLED)
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_VARIABLE_REPLY(resolve_helper, helper_id, address, PROTOCOL_JIT_MODE),
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_VARIABLE_REPLY(resolve_map, map_handle, address, PROTOCOL_JIT_MODE),
#else
DECLARE_PROTOCOL_HANDLER_INVALID(EBPF_PROTOCOL_VARIABLE_REQUEST_VARIABLE_REPLY),
DECLARE_PROTOCOL_HANDLER_INVALID(EBPF_PROTOCOL_VARIABLE_REQUEST_VARIABLE_REPLY),
#endif
#if !defined(CONFIG_BPF_JIT_DISABLED) || !defined(CONFIG_BPF_INTERPRETER_DISABLED)
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_FIXED_REPLY(create_program, data, PROTOCOL_JIT_OR_INTERPRET_MODE),
#else
DECLARE_PROTOCOL_HANDLER_INVALID(EBPF_PROTOCOL_VARIABLE_REQUEST_FIXED_REPLY),
#endif
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_FIXED_REPLY(create_map, data, PROTOCOL_ALL_MODES),
#if !defined(CONFIG_BPF_JIT_DISABLED) || !defined(CONFIG_BPF_INTERPRETER_DISABLED)
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_NO_REPLY(load_code, code, PROTOCOL_JIT_OR_INTERPRET_MODE),
#else
DECLARE_PROTOCOL_HANDLER_INVALID(EBPF_PROTOCOL_VARIABLE_REQUEST_NO_REPLY),
#endif
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_VARIABLE_REPLY(map_find_element, key, value, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_NO_REPLY(map_update_element, data, PROTOCOL_ALL_MODES),
Expand All @@ -2500,6 +2512,8 @@ static ebpf_protocol_handler_t _ebpf_protocol_handlers[] = {
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_NO_REPLY(close_handle, PROTOCOL_ALL_MODES),
#if !defined(CONFIG_BPF_JIT_DISABLED)
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_FIXED_REPLY(get_ec_function, PROTOCOL_JIT_MODE),
#else
DECLARE_PROTOCOL_HANDLER_INVALID(EBPF_PROTOCOL_FIXED_REQUEST_FIXED_REPLY),
#endif
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_VARIABLE_REPLY(get_program_info, data, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_VARIABLE_REPLY(get_pinned_map_info, data, PROTOCOL_ALL_MODES),
Expand Down Expand Up @@ -2613,6 +2627,11 @@ ebpf_core_invoke_protocol_handler(
goto Done;
}

// If the dispatch function is NULL, the operation is not supported.
if (_ebpf_protocol_handlers[operation_id].dispatch.default_case == NULL) {
return EBPF_BLOCKED_BY_POLICY;
}

if (input_buffer_length > UINT16_MAX) {
retval = EBPF_INVALID_ARGUMENT;
goto Done;
Expand Down
8 changes: 0 additions & 8 deletions libs/execution_context/ebpf_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,11 @@

typedef enum _ebpf_operation_id
{
#if !defined(CONFIG_BPF_JIT_DISABLED)
EBPF_OPERATION_RESOLVE_HELPER,
EBPF_OPERATION_RESOLVE_MAP,
#endif
#if !defined(CONFIG_BPF_JIT_DISABLED) || !defined(CONFIG_BPF_INTERPRETER_DISABLED)
EBPF_OPERATION_CREATE_PROGRAM,
#endif
EBPF_OPERATION_CREATE_MAP,
#if !defined(CONFIG_BPF_JIT_DISABLED) || !defined(CONFIG_BPF_INTERPRETER_DISABLED)
EBPF_OPERATION_LOAD_CODE,
#endif
EBPF_OPERATION_MAP_FIND_ELEMENT,
EBPF_OPERATION_MAP_UPDATE_ELEMENT,
EBPF_OPERATION_MAP_UPDATE_ELEMENT_WITH_HANDLE,
Expand All @@ -31,9 +25,7 @@ typedef enum _ebpf_operation_id
EBPF_OPERATION_LINK_PROGRAM,
EBPF_OPERATION_UNLINK_PROGRAM,
EBPF_OPERATION_CLOSE_HANDLE,
#if !defined(CONFIG_BPF_JIT_DISABLED)
EBPF_OPERATION_GET_EC_FUNCTION,
#endif
EBPF_OPERATION_GET_PROGRAM_INFO,
EBPF_OPERATION_GET_PINNED_MAP_INFO,
EBPF_OPERATION_GET_LINK_HANDLE_BY_ID,
Expand Down
50 changes: 47 additions & 3 deletions libs/execution_context/unit/execution_context_unit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,25 @@ extern bool _ebpf_platform_code_integrity_enabled;
std::map<std::string, ebpf_handle_t> map_handles; \
create_various_objects(program_handles, map_handles);

#if defined(CONFIG_BPF_JIT_DISABLED) || defined(CONFIG_BPF_INTERPRETER_DISABLED)
void
test_blocked_by_policy(ebpf_operation_id_t operation)
{
NEGATIVE_TEST_PROLOG();

ebpf_result_t expected_result = EBPF_BLOCKED_BY_POLICY;

std::vector<uint8_t> request(sizeof(ebpf_operation_header_t));
std::vector<uint8_t> reply(sizeof(ebpf_operation_header_t));

REQUIRE(invoke_protocol(operation, request, reply) == expected_result);

// Use a request buffer larger than ebpf_operation_header_t, and try again.
request.resize(request.size() + 10);
REQUIRE(invoke_protocol(operation, request, reply) == expected_result);
}
#endif

#if !defined(CONFIG_BPF_JIT_DISABLED)
// These tests exist to verify ebpf_core's parsing of messages.
// See libbpf_test.cpp for invalid parameter but correctly formed message cases.
Expand Down Expand Up @@ -1316,7 +1335,17 @@ TEST_CASE("EBPF_OPERATION_RESOLVE_MAP", "[execution_context][negative]")
resolve_map_request->program_handle = program_handles[0];
REQUIRE(invoke_protocol(EBPF_OPERATION_RESOLVE_MAP, request, reply) == EBPF_INVALID_ARGUMENT);
}
#endif
#else
TEST_CASE("EBPF_OPERATION_RESOLVE_HELPER", "[execution_context][negative]")
{
test_blocked_by_policy(EBPF_OPERATION_RESOLVE_HELPER);
}

TEST_CASE("EBPF_OPERATION_RESOLVE_MAP", "[execution_context][negative]")
{
test_blocked_by_policy(EBPF_OPERATION_RESOLVE_MAP);
}
#endif // !defined(CONFIG_BPF_JIT_DISABLED)

#if !defined(CONFIG_BPF_JIT_DISABLED) || !defined(CONFIG_BPF_INTERPRETER_DISABLED)
TEST_CASE("EBPF_OPERATION_CREATE_PROGRAM", "[execution_context][negative]")
Expand Down Expand Up @@ -1373,7 +1402,12 @@ TEST_CASE("EBPF_OPERATION_CREATE_PROGRAM", "[execution_context][negative]")
create_program_request->program_name_offset = EBPF_OFFSET_OF(ebpf_operation_create_program_request_t, data);
REQUIRE(invoke_protocol(EBPF_OPERATION_CREATE_PROGRAM, request, reply) == EBPF_INVALID_ARGUMENT);
}
#endif
#else
TEST_CASE("EBPF_OPERATION_CREATE_PROGRAM", "[execution_context][negative]")
{
test_blocked_by_policy(EBPF_OPERATION_CREATE_PROGRAM);
}
#endif // !defined(CONFIG_BPF_JIT_DISABLED) || !defined(CONFIG_BPF_INTERPRETER_DISABLED)

TEST_CASE("EBPF_OPERATION_CREATE_MAP", "[execution_context][negative]")
{
Expand Down Expand Up @@ -1465,7 +1499,12 @@ TEST_CASE("EBPF_OPERATION_LOAD_CODE", "[execution_context][negative]")
}
_ebpf_platform_code_integrity_enabled = false;
}
#endif
#else
TEST_CASE("EBPF_OPERATION_LOAD_CODE", "[execution_context][negative]")
{
test_blocked_by_policy(EBPF_OPERATION_LOAD_CODE);
}
#endif // !defined(CONFIG_BPF_JIT_DISABLED) || !defined(CONFIG_BPF_INTERPRETER_DISABLED)

TEST_CASE("EBPF_OPERATION_LOAD_NATIVE_MODULE", "[execution_context][negative]")
{
Expand Down Expand Up @@ -1738,6 +1777,11 @@ TEST_CASE("EBPF_OPERATION_GET_EC_FUNCTION", "[execution_context][negative]")
// Wrong EC function.
REQUIRE(invoke_protocol(EBPF_OPERATION_GET_EC_FUNCTION, request, reply) == EBPF_INVALID_ARGUMENT);
}
#else
TEST_CASE("EBPF_OPERATION_GET_EC_FUNCTION", "[execution_context][negative]")
{
test_blocked_by_policy(EBPF_OPERATION_GET_EC_FUNCTION);
}
#endif

TEST_CASE("EBPF_OPERATION_GET_PROGRAM_INFO", "[execution_context][negative]")
Expand Down
61 changes: 33 additions & 28 deletions tests/end_to_end/end_to_end.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1663,15 +1663,10 @@ _xdp_reflect_packet_test(ebpf_execution_type_t execution_type, ADDRESS_FAMILY ad
program_info_provider_t xdp_program_info;
REQUIRE(xdp_program_info.initialize(EBPF_PROGRAM_TYPE_XDP_TEST) == EBPF_SUCCESS);
uint32_t ifindex = 0;
const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? "reflect_packet_um.dll" : "reflect_packet.o");
program_load_attach_helper_t program_helper;
program_helper.initialize(
SAMPLE_PATH "reflect_packet.o",
BPF_PROG_TYPE_XDP_TEST,
"reflect_packet",
execution_type,
&ifindex,
sizeof(ifindex),
hook);
file_name, BPF_PROG_TYPE_XDP_TEST, "reflect_packet", execution_type, &ifindex, sizeof(ifindex), hook);

// Dummy UDP datagram with fake IP and MAC addresses.
udp_packet_t packet(address_family);
Expand All @@ -1698,6 +1693,18 @@ _xdp_reflect_packet_test(ebpf_execution_type_t execution_type, ADDRESS_FAMILY ad
}
}

static void
_xdp_reflect_packet_test_v4(ebpf_execution_type_t execution_type)
{
_xdp_reflect_packet_test(execution_type, AF_INET);
}

static void
_xdp_reflect_packet_test_v6(ebpf_execution_type_t execution_type)
{
_xdp_reflect_packet_test(execution_type, AF_INET6);
}

static void
_xdp_encap_reflect_packet_test(ebpf_execution_type_t execution_type, ADDRESS_FAMILY address_family)
{
Expand All @@ -1708,15 +1715,11 @@ _xdp_encap_reflect_packet_test(ebpf_execution_type_t execution_type, ADDRESS_FAM
program_info_provider_t xdp_program_info;
REQUIRE(xdp_program_info.initialize(EBPF_PROGRAM_TYPE_XDP_TEST) == EBPF_SUCCESS);
uint32_t ifindex = 0;
const char* file_name =
(execution_type == EBPF_EXECUTION_NATIVE ? "encap_reflect_packet_um.dll" : "encap_reflect_packet.o");
program_load_attach_helper_t program_helper;
program_helper.initialize(
SAMPLE_PATH "encap_reflect_packet.o",
BPF_PROG_TYPE_XDP_TEST,
"encap_reflect_packet",
execution_type,
&ifindex,
sizeof(ifindex),
hook);
file_name, BPF_PROG_TYPE_XDP_TEST, "encap_reflect_packet", execution_type, &ifindex, sizeof(ifindex), hook);

// Dummy UDP datagram with fake IP and MAC addresses.
udp_packet_t packet(address_family);
Expand Down Expand Up @@ -1753,6 +1756,18 @@ _xdp_encap_reflect_packet_test(ebpf_execution_type_t execution_type, ADDRESS_FAM
}
}

static void
_xdp_encap_reflect_packet_test_v4(ebpf_execution_type_t execution_type)
{
_xdp_encap_reflect_packet_test(execution_type, AF_INET);
}

static void
_xdp_encap_reflect_packet_test_v6(ebpf_execution_type_t execution_type)
{
_xdp_encap_reflect_packet_test(execution_type, AF_INET6);
}

#if !defined(CONFIG_BPF_INTERPRETER_DISABLED)
TEST_CASE("printk", "[end_to_end]")
{
Expand Down Expand Up @@ -1811,20 +1826,10 @@ TEST_CASE("printk", "[end_to_end]")
}
#endif

TEST_CASE("xdp-reflect-v4-jit", "[xdp_tests]") { _xdp_reflect_packet_test(EBPF_EXECUTION_JIT, AF_INET); }
TEST_CASE("xdp-reflect-v6-jit", "[xdp_tests]") { _xdp_reflect_packet_test(EBPF_EXECUTION_JIT, AF_INET6); }
TEST_CASE("xdp-reflect-v4-interpret", "[xdp_tests]") { _xdp_reflect_packet_test(EBPF_EXECUTION_INTERPRET, AF_INET); }
TEST_CASE("xdp-reflect-v6-interpret", "[xdp_tests]") { _xdp_reflect_packet_test(EBPF_EXECUTION_INTERPRET, AF_INET6); }
TEST_CASE("xdp-encap-reflect-v4-jit", "[xdp_tests]") { _xdp_encap_reflect_packet_test(EBPF_EXECUTION_JIT, AF_INET); }
TEST_CASE("xdp-encap-reflect-v6-jit", "[xdp_tests]") { _xdp_encap_reflect_packet_test(EBPF_EXECUTION_JIT, AF_INET6); }
TEST_CASE("xdp-encap-reflect-v4-interpret", "[xdp_tests]")
{
_xdp_encap_reflect_packet_test(EBPF_EXECUTION_INTERPRET, AF_INET);
}
TEST_CASE("xdp-encap-reflect-v6-interpret", "[xdp_tests]")
{
_xdp_encap_reflect_packet_test(EBPF_EXECUTION_INTERPRET, AF_INET6);
}
DECLARE_ALL_TEST_CASES("xdp-reflect-v4", "[xdp_tests]", _xdp_reflect_packet_test_v4);
DECLARE_ALL_TEST_CASES("xdp-reflect-v6", "[xdp_tests]", _xdp_reflect_packet_test_v6);
DECLARE_ALL_TEST_CASES("xdp-encap-reflect-v4", "[xdp_tests]", _xdp_encap_reflect_packet_test_v4);
DECLARE_ALL_TEST_CASES("xdp-encap-reflect-v6", "[xdp_tests]", _xdp_encap_reflect_packet_test_v6);

#if !defined(CONFIG_BPF_INTERPRETER_DISABLED) || !defined(CONFIG_BPF_JIT_DISABLED)
static void
Expand Down
2 changes: 2 additions & 0 deletions tests/end_to_end/netsh_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ verify_no_programs_exist()
"====== ==== ===== ========= ============= ====================\n");
}

#if !defined(CONFIG_BPF_JIT_DISABLED) || !defined(CONFIG_BPF_INTERPRETER_DISABLED)
TEST_CASE("pin first program", "[netsh][programs]")
{
_test_helper_netsh test_helper;
Expand Down Expand Up @@ -949,6 +950,7 @@ TEST_CASE("cgroup_sock_addr compartment parameter", "[netsh][programs]")

ebpf_epoch_synchronize();
}
#endif // !defined(CONFIG_BPF_JIT_DISABLED) || !defined(CONFIG_BPF_INTERPRETER_DISABLED)

TEST_CASE("show processes", "[netsh][processes]")
{
Expand Down
6 changes: 6 additions & 0 deletions tests/unit/test.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@
<AdditionalDependencies>mincore.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);$(VC_LibraryPath_VC_x64_Desktop);%(Link.AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy $(SolutionDir)$(Platform)\Debug\usersim.dll $(OutDir) /F /Y</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='FuzzerDebug|x64'">
<ClCompile>
Expand Down Expand Up @@ -174,6 +177,9 @@
<AdditionalDependencies>mincore.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);$(VC_LibraryPath_VC_x64_Desktop);%(Link.AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy $(SolutionDir)$(Platform)\Release\usersim.dll $(OutDir) /F /Y</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\..\external\Catch2\build\src\Catch2WithMain.vcxproj">
Expand Down
8 changes: 8 additions & 0 deletions tools/bpf2c/templates/user_mode_bpf2c.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='NativeOnlyRelease'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup Condition="$(ResourceFile)!=''">
<ResourceCompile Include="$(ResourceFile)" />
</ItemGroup>
Expand Down
Loading