Skip to content

Commit

Permalink
WiP - Add rundown audit trail
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhiren Vispute authored and Dhiren Vispute committed Feb 28, 2024
1 parent f421d23 commit 4129cfc
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 213 deletions.
205 changes: 7 additions & 198 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,176 +68,28 @@ jobs:
build_nuget: true
configurations: '["NativeOnlyDebug", "NativeOnlyRelease"]'

# Run the unit tests in GitHub.
unit_tests_appverif:
# Always run this job.
needs: regular
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/reusable-test.yml
with:
name: unit_tests
pre_test: appverif -enable Exceptions Handles Heaps Leak 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
environment: windows-2022
code_coverage: true
gather_dumps: true
capture_etw: true
leak_detection: true

# Run the unit tests in GitHub.
unit_tests:
# Always run this job.
needs: regular
if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group'
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
environment: windows-2022
code_coverage: true
gather_dumps: true
capture_etw: true
leak_detection: true

# Run the netebpfext unit tests in GitHub.
netebpf_ext_unit_tests:
# Always run this job.
needs: regular
if: github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/reusable-test.yml
with:
name: netebpf_ext_unit_tests
pre_test: appverif -enable Exceptions Handles Heaps Leak Locks Memory SRWLock Threadpool TLS DangerousAPIs DirtyStacks TimeRollOver -for unit_tests.exe
test_command: .\netebpfext_unit.exe -d yes
build_artifact: Build-x64
environment: windows-2022
code_coverage: true
gather_dumps: true
capture_etw: true
leak_detection: true

# Run the bpf2c tests in GitHub.
bpf2c:
# Always run this job.
needs: regular
if: github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/reusable-test.yml
with:
test_command: .\bpf2c_tests.exe -d yes
name: bpf2c
build_artifact: Build-x64
environment: windows-2022
vs_dev: true
code_coverage: true
gather_dumps: true
capture_etw: true

# Run the bpf2c conformance tests in GitHub.
bpf2c_conformance:
# Always run this job.
# Run multi-threaded stress tests with 'restart extension' enabled
# against the kernel mode eBPF sub-system.
aaa_km_mt_stress_tests_restart_extension:
needs: regular
if: github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/reusable-test.yml
with:
pre_test: Invoke-WebRequest https://github.com/Alan-Jowett/bpf_conformance/releases/download/v0.0.5/bpf_conformance_runner.exe -OutFile bpf_conformance_runner.exe
test_command: .\bpf_conformance_runner.exe --test_file_directory %SOURCE_ROOT%\external\ebpf-verifier\external\bpf_conformance\tests --cpu_version v4 --exclude_regex local --plugin_path bpf2c_plugin.exe --debug true --plugin_options "--include %SOURCE_ROOT%\include"
name: bpf2c_conformance
build_artifact: Build-x64
environment: windows-2022
vs_dev: true
code_coverage: true
gather_dumps: true
capture_etw: true

# Run the driver tests on self-hosted runners.
driver_ws2019:
# Always run this job.
# Only run this on repos that have self-host runners.
needs: regular
if: github.repository == 'microsoft/ebpf-for-windows' && (github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch')
uses: ./.github/workflows/reusable-test.yml
with:
pre_test: .\setup_ebpf_cicd_tests.ps1 -KmTracing $true -KmTraceType "file"
test_command: .\execute_ebpf_cicd_tests.ps1 -TestMode "CI/CD"
name: aaa_km_mt_stress_tests_restart_extension
pre_test: .\setup_ebpf_cicd_tests.ps1 -KmTracing $true -KmTraceType "memory"
test_command: .\execute_ebpf_cicd_tests.ps1 -TestMode "Stress" -Options @("RestartExtension")
post_test: .\cleanup_ebpf_cicd_tests.ps1 -KmTracing $true
name: driver_ws2019
build_artifact: Build-x64
environment: ebpf_cicd_tests_ws2019
# driver test copies dumps to testlog folder.
gather_dumps: false
# driver tests manually gather code coverage
code_coverage: false

# Run the driver tests on self-hosted runners.
driver_ws2022:
# Always run this job.
# Only run this on repos that have self-host runners.
needs: regular
if: github.repository == 'microsoft/ebpf-for-windows' && (github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch')
uses: ./.github/workflows/reusable-test.yml
with:
pre_test: .\setup_ebpf_cicd_tests.ps1 -KmTracing $true -KmTraceType "file"
test_command: .\execute_ebpf_cicd_tests.ps1 -TestMode "CI/CD"
post_test: .\cleanup_ebpf_cicd_tests.ps1 -KmTracing $true
name: driver_ws2022
build_artifact: Build-x64
environment: ebpf_cicd_tests_ws2022
# driver test copies dumps to testlog folder.
# For this test, we only want kernel mode dumps and not user mode dumps.
gather_dumps: false
# driver tests manually gather code coverage
code_coverage: false

# Run the native-only driver tests on self-hosted runners.
driver_native_only_ws2019:
# Always run this job.
# Only run this on repos that have self-host runners.
needs: regular_native-only
if: github.repository == 'microsoft/ebpf-for-windows' && (github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch')
uses: ./.github/workflows/reusable-test.yml
with:
pre_test: .\setup_ebpf_cicd_tests.ps1 -KmTracing $true -KmTraceType "file"
test_command: .\execute_ebpf_cicd_tests.ps1 -TestMode "CI/CD"
post_test: .\cleanup_ebpf_cicd_tests.ps1 -KmTracing $true
name: driver_native_only_ws2019
build_artifact: Build-x64-native-only
environment: ebpf_cicd_tests_ws2019
# driver test copies dumps to testlog folder.
gather_dumps: false
# driver tests manually gather code coverage
code_coverage: false
configurations: '["NativeOnlyDebug", "NativeOnlyRelease"]'

driver_native_only_ws2022:
# Always run this job.
# Only run this on repos that have self-host runners.
needs: regular_native-only
if: github.repository == 'microsoft/ebpf-for-windows' && (github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch')
uses: ./.github/workflows/reusable-test.yml
with:
pre_test: .\setup_ebpf_cicd_tests.ps1 -KmTracing $true -KmTraceType "file"
test_command: .\execute_ebpf_cicd_tests.ps1 -TestMode "CI/CD"
post_test: .\cleanup_ebpf_cicd_tests.ps1 -KmTracing $true
name: driver_native_only_ws2022
build_artifact: Build-x64-native-only
environment: ebpf_cicd_tests_ws2022
# driver test copies dumps to testlog folder.
gather_dumps: false
# driver tests manually gather code coverage
code_coverage: false
configurations: '["NativeOnlyDebug", "NativeOnlyRelease"]'

ossar:
# Always run this job.
needs: regular
if: github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/ossar-scan.yml
with:
build_artifact: Build-x64

# Additional jobs to run on pull and schedule only (skip push).
# ---------------------------------------------------------------------------
Expand All @@ -262,19 +114,6 @@ jobs:
build_artifact: Build-x64-Sanitize
build_options: /p:AddressSanitizer='True'

bpf2c_fuzzer:
needs: regular
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
uses: ./.github/workflows/reusable-test.yml
with:
name: bpf2c_fuzzer
test_command: .\bpf2c_fuzzer.exe bpf2c_fuzzer_corpus -use_value_profile=1 -max_total_time=300 -artifact_prefix=Artifacts\
build_artifact: Build-x64
environment: windows-2022
code_coverage: false
gather_dumps: true
configurations: '["FuzzerDebug"]'

bpf2c_fuzzer_scheduled:
needs: regular
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
Expand Down Expand Up @@ -359,36 +198,6 @@ jobs:
gather_dumps: true
configurations: '["FuzzerDebug"]'

# Run Cilium regression tests in GitHub.
cilium_tests:
needs: regular
# Only run on schedule and pull request.
if: github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/reusable-test.yml
with:
name: cilium_tests
test_command: .\cilium_tests.exe -d yes
build_artifact: Build-x64
environment: windows-2022
code_coverage: false
gather_dumps: true

# Run the quick stress tests in GitHub.
stress:
needs: regular
# Only run on schedule and pull request.
if: github.event_name == 'schedule' || github.event_name == 'pull_request' || github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/reusable-test.yml
with:
name: stress
# Until there is a dedicated stress test, re-use the perf test.
test_command: .\ebpf_performance.exe -d yes
build_artifact: Build-x64
environment: windows-2022
# No code coverage on stress.
code_coverage: false
gather_dumps: true

# Run the unit tests in GitHub with address sanitizer.
sanitize_unit_tests:
needs: sanitize
Expand Down
2 changes: 1 addition & 1 deletion netebpfext/net_ebpf_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ net_ebpf_extension_wfp_filter_context_create(
local_filter_context->reference_count = 1; // Initial reference.
local_filter_context->client_context = client_context;

if (!net_ebpf_extension_hook_client_enter_rundown(
if (!NET_EBPF_EXTENSION_HOOK_CLIENT_ENTER_RUNDOWN_EX(
(net_ebpf_extension_hook_client_t*)local_filter_context->client_context)) {

// We're setting up the filter context here and as this is the very first (and exclusive) attempt to acquire
Expand Down
8 changes: 4 additions & 4 deletions netebpfext/net_ebpf_ext_bind.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ net_ebpf_ext_resource_allocation_classify(
}

attached_client = (net_ebpf_extension_hook_client_t*)filter_context->client_context;
if (!net_ebpf_extension_hook_client_enter_rundown(attached_client)) {
if (!NET_EBPF_EXTENSION_HOOK_CLIENT_ENTER_RUNDOWN_EX(attached_client)) {
NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS(
NET_EBPF_EXT_TRACELOG_LEVEL_VERBOSE,
NET_EBPF_EXT_TRACELOG_KEYWORD_BIND,
Expand Down Expand Up @@ -321,7 +321,7 @@ net_ebpf_ext_resource_allocation_classify(

Exit:
if (attached_client) {
net_ebpf_extension_hook_client_leave_rundown(attached_client);
NET_EBPF_EXTENSION_HOOK_CLIENT_LEAVE_RUNDOWN_EX(attached_client);
}
return;
}
Expand Down Expand Up @@ -364,7 +364,7 @@ net_ebpf_ext_resource_release_classify(
}

attached_client = (net_ebpf_extension_hook_client_t*)filter_context->client_context;
if (!net_ebpf_extension_hook_client_enter_rundown(attached_client)) {
if (!NET_EBPF_EXTENSION_HOOK_CLIENT_ENTER_RUNDOWN_EX(attached_client)) {
NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS(
NET_EBPF_EXT_TRACELOG_LEVEL_VERBOSE,
NET_EBPF_EXT_TRACELOG_KEYWORD_BIND,
Expand Down Expand Up @@ -399,7 +399,7 @@ net_ebpf_ext_resource_release_classify(

Exit:
if (attached_client) {
net_ebpf_extension_hook_client_leave_rundown(attached_client);
NET_EBPF_EXTENSION_HOOK_CLIENT_LEAVE_RUNDOWN_EX(attached_client);
}
return;
}
Expand Down
53 changes: 53 additions & 0 deletions netebpfext/net_ebpf_ext_hook_provider.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@ typedef struct _net_ebpf_extension_hook_provider
#define RELEASE_PUSH_LOCK_EXCLUSIVE(lock) _RELEASE_PUSH_LOCK(lock, Exclusive)
#define RELEASE_PUSH_LOCK_SHARED(lock) _RELEASE_PUSH_LOCK(lock, Shared)

KSPIN_LOCK _rundown_audit_trail_lock;
uint32_t _rundown_ref_count = 0;
uint32_t _rundown_audit_trail_index = 0;

typedef struct _rundown_audit_trail_entry
{
rundown_op_type_t op_type;
uint32_t line_num;
char* calling_func;
net_ebpf_ext_hook_client_rundown_t rundown;

} rundown_audit_trail_entry_t;

rundown_audit_trail_entry_t _rundown_audit_trail[8192];
uint32_t _rundown_audit_trail_index_max = (sizeof(_rundown_audit_trail) / sizeof(rundown_audit_trail_entry_t));

/**
* @brief Initialize the hook client rundown state.
*
Expand Down Expand Up @@ -170,13 +186,49 @@ net_ebpf_extension_hook_client_enter_rundown(_Inout_ net_ebpf_extension_hook_cli
return status;
}

bool
net_ebpf_extension_hook_client_enter_rundown_ex(
_Inout_ net_ebpf_extension_hook_client_t* hook_client, char* calling_func, uint32_t line_num)
{
KIRQL old_irql;
BOOL status;

KeAcquireSpinLock(&_rundown_audit_trail_lock, &old_irql);
status = net_ebpf_extension_hook_client_enter_rundown(hook_client);
if (status) {
_rundown_audit_trail[_rundown_audit_trail_index].op_type = RUNDOWN_OP_TYPE_ENTER;
_rundown_audit_trail[_rundown_audit_trail_index].line_num = line_num;
_rundown_audit_trail[_rundown_audit_trail_index].calling_func = calling_func;
_rundown_audit_trail[_rundown_audit_trail_index].rundown = hook_client->rundown;
_rundown_audit_trail_index++;
}
KeReleaseSpinLock(&_rundown_audit_trail_lock, old_irql);
return status;
}

void
net_ebpf_extension_hook_client_leave_rundown(_Inout_ net_ebpf_extension_hook_client_t* hook_client)
{
net_ebpf_ext_hook_client_rundown_t* rundown = &hook_client->rundown;
ExReleaseRundownProtection(&rundown->protection);
}

void
net_ebpf_extension_hook_client_leave_rundown_ex(
_Inout_ net_ebpf_extension_hook_client_t* hook_client, char* calling_func, uint32_t line_num)
{
KIRQL old_irql;

KeAcquireSpinLock(&_rundown_audit_trail_lock, &old_irql);
net_ebpf_extension_hook_client_leave_rundown(hook_client);
_rundown_audit_trail[_rundown_audit_trail_index].op_type = RUNDOWN_OP_TYPE_LEAVE;
_rundown_audit_trail[_rundown_audit_trail_index].line_num = line_num;
_rundown_audit_trail[_rundown_audit_trail_index].calling_func = calling_func;
_rundown_audit_trail[_rundown_audit_trail_index].rundown = hook_client->rundown;
_rundown_audit_trail_index++;
KeReleaseSpinLock(&_rundown_audit_trail_lock, old_irql);
}

const ebpf_extension_data_t*
net_ebpf_extension_hook_client_get_client_data(_In_ const net_ebpf_extension_hook_client_t* hook_client)
{
Expand Down Expand Up @@ -490,6 +542,7 @@ net_ebpf_extension_hook_provider_register(
memset(local_provider_context, 0, sizeof(net_ebpf_extension_hook_provider_t));
ExInitializePushLock(&local_provider_context->lock);
InitializeListHead(&local_provider_context->attached_clients_list);
KeInitializeSpinLock(&_rundown_audit_trail_lock);

characteristics = &local_provider_context->characteristics;
characteristics->Length = sizeof(NPI_PROVIDER_CHARACTERISTICS);
Expand Down
Loading

0 comments on commit 4129cfc

Please sign in to comment.