diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index a7d4fbbc95..0ec34f5dba 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -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. diff --git a/libs/execution_context/ebpf_core.c b/libs/execution_context/ebpf_core.c index 5ee5de801d..e0d5180b6a 100644 --- a/libs/execution_context/ebpf_core.c +++ b/libs/execution_context/ebpf_core.c @@ -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; @@ -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), @@ -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), @@ -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; diff --git a/libs/execution_context/ebpf_protocol.h b/libs/execution_context/ebpf_protocol.h index 9cac5c347c..b3d1157119 100644 --- a/libs/execution_context/ebpf_protocol.h +++ b/libs/execution_context/ebpf_protocol.h @@ -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, @@ -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, diff --git a/libs/execution_context/unit/execution_context_unit_test.cpp b/libs/execution_context/unit/execution_context_unit_test.cpp index 7c5703bdc7..42a836b073 100644 --- a/libs/execution_context/unit/execution_context_unit_test.cpp +++ b/libs/execution_context/unit/execution_context_unit_test.cpp @@ -1245,6 +1245,25 @@ extern bool _ebpf_platform_code_integrity_enabled; std::map 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 request(sizeof(ebpf_operation_header_t)); + std::vector 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. @@ -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]") @@ -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]") { @@ -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]") { @@ -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]") diff --git a/tests/end_to_end/end_to_end.cpp b/tests/end_to_end/end_to_end.cpp index e30fadd4eb..68994543ba 100644 --- a/tests/end_to_end/end_to_end.cpp +++ b/tests/end_to_end/end_to_end.cpp @@ -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); @@ -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) { @@ -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); @@ -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]") { @@ -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 diff --git a/tests/end_to_end/netsh_test.cpp b/tests/end_to_end/netsh_test.cpp index 9edbd80d38..4d9bee7030 100644 --- a/tests/end_to_end/netsh_test.cpp +++ b/tests/end_to_end/netsh_test.cpp @@ -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; @@ -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]") { diff --git a/tests/unit/test.vcxproj b/tests/unit/test.vcxproj index af742c55a3..4549c2c299 100644 --- a/tests/unit/test.vcxproj +++ b/tests/unit/test.vcxproj @@ -131,6 +131,9 @@ mincore.lib;%(AdditionalDependencies) $(OutDir);$(VC_LibraryPath_VC_x64_Desktop);%(Link.AdditionalLibraryDirectories) + + xcopy $(SolutionDir)$(Platform)\Debug\usersim.dll $(OutDir) /F /Y + @@ -174,6 +177,9 @@ mincore.lib;%(AdditionalDependencies) $(OutDir);$(VC_LibraryPath_VC_x64_Desktop);%(Link.AdditionalLibraryDirectories) + + xcopy $(SolutionDir)$(Platform)\Release\usersim.dll $(OutDir) /F /Y + diff --git a/tools/bpf2c/templates/user_mode_bpf2c.vcxproj b/tools/bpf2c/templates/user_mode_bpf2c.vcxproj index ff392cec93..6fa876159f 100644 --- a/tools/bpf2c/templates/user_mode_bpf2c.vcxproj +++ b/tools/bpf2c/templates/user_mode_bpf2c.vcxproj @@ -159,6 +159,14 @@ Default + + + MaxSpeed + true + true + Default + +