From f61aaa14709faac0e44693502d93c5fde101294f Mon Sep 17 00:00:00 2001 From: Alan Jowett Date: Tue, 27 Feb 2024 18:07:08 -0800 Subject: [PATCH] Add new hook provider for process creation and termination. Signed-off-by: Alan Jowett --- ebpf-for-windows.sln | 135 ++++--- external/usersim | 2 +- include/ebpf_nethooks.h | 33 ++ include/ebpf_program_attach_type_guids.h | 22 ++ include/ebpf_structs.h | 17 + netebpfext/net_ebpf_ext.c | 17 + netebpfext/net_ebpf_ext_process.c | 367 ++++++++++++++++++ netebpfext/net_ebpf_ext_process.h | 22 ++ netebpfext/net_ebpf_ext_program_info.h | 13 + netebpfext/net_ebpf_ext_tracelog.c | 2 + netebpfext/net_ebpf_ext_tracelog.h | 4 +- netebpfext/sys/netebpfext.vcxproj | 6 + netebpfext/sys/netebpfext.vcxproj.filters | 6 + netebpfext/user/netebpfext_user.vcxproj | 2 + .../user/netebpfext_user.vcxproj.filters | 6 + tests/end_to_end/helpers.h | 8 + tests/netebpfext_unit/netebpfext_unit.cpp | 84 +++- tests/sample/process_monitor.c | 110 ++++++ tests/sample/sample.vcxproj | 15 + tests/unit/libbpf_test.cpp | 71 +++- .../export_program_info.cpp | 2 + tools/process_monitor/process_monitor.cpp | 145 +++++++ tools/process_monitor/process_monitor.vcxproj | 148 +++++++ .../process_monitor.vcxproj.filters | 26 ++ 24 files changed, 1213 insertions(+), 50 deletions(-) create mode 100644 netebpfext/net_ebpf_ext_process.c create mode 100644 netebpfext/net_ebpf_ext_process.h create mode 100644 tests/sample/process_monitor.c create mode 100644 tools/process_monitor/process_monitor.cpp create mode 100644 tools/process_monitor/process_monitor.vcxproj create mode 100644 tools/process_monitor/process_monitor.vcxproj.filters diff --git a/ebpf-for-windows.sln b/ebpf-for-windows.sln index 48d9f6c1a3..e5fdcf0edd 100644 --- a/ebpf-for-windows.sln +++ b/ebpf-for-windows.sln @@ -213,11 +213,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "redist-package", "tools\red EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ebpf_stress_tests_km", "tests\stress\km\ebpf_stress_tests_km.vcxproj", "{4F082524-9496-44FA-8CBA-4BC0BDC62568}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ebpf_store_helper_um", "libs\store_helper\user\ebpf_store_helper_um.vcxproj", "{AA933B9F-B5D8-4AA8-AC18-98FE1A161E8A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ebpf_store_helper", "libs\store_helper\user\ebpf_store_helper_um.vcxproj", "{AA933B9F-B5D8-4AA8-AC18-98FE1A161E8A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usersim", "external\usersim\src\usersim.vcxproj", "{030A7AC6-14DC-45CF-AF34-891057AB1402}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbtf", "external\ebpf-verifier\build\external\libbtf\libbtf\libbtf.vcxproj", "{89A12D43-9B91-3960-A6BF-E506122C207A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbtf", "external\ebpf-verifier\build\external\libbtf\libbtf\libbtf.vcxproj", "{018D6472-F71C-34B5-BB9B-6BC2A506DB5E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usersim_dll_skeleton", "external\usersim\usersim_dll_skeleton\usersim_dll_skeleton.vcxproj", "{1937DB41-F3EB-4955-A636-6386DCB394F6}" EndProject @@ -249,6 +249,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_ebpf_ext", "undocked EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_ext_app", "tests\sample\ext\app\sample_ext_app.vcxproj", "{6D365515-DE92-4CEB-AB3D-5608719A8886}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "process_monitor", "tools\process_monitor\process_monitor.vcxproj", "{3DBF8A96-3883-448A-8BD3-B8C913A27F09}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -2667,48 +2669,48 @@ Global {030A7AC6-14DC-45CF-AF34-891057AB1402}.RelWithDebInfo|x64.Build.0 = Release|x64 {030A7AC6-14DC-45CF-AF34-891057AB1402}.RelWithDebInfo|x86.ActiveCfg = Release|Win32 {030A7AC6-14DC-45CF-AF34-891057AB1402}.RelWithDebInfo|x86.Build.0 = Release|Win32 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Debug|ARM64.ActiveCfg = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Debug|ARM64.Build.0 = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Debug|x64.ActiveCfg = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Debug|x64.Build.0 = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Debug|x86.ActiveCfg = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Debug|x86.Build.0 = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.FuzzerDebug|ARM64.ActiveCfg = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.FuzzerDebug|ARM64.Build.0 = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.FuzzerDebug|x64.ActiveCfg = FuzzerDebug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.FuzzerDebug|x64.Build.0 = FuzzerDebug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.FuzzerDebug|x86.ActiveCfg = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.FuzzerDebug|x86.Build.0 = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.MinSizeRel|ARM64.ActiveCfg = MinSizeRel|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.MinSizeRel|ARM64.Build.0 = MinSizeRel|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.MinSizeRel|x86.Build.0 = MinSizeRel|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyDebug|ARM64.ActiveCfg = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyDebug|ARM64.Build.0 = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyDebug|x64.ActiveCfg = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyDebug|x64.Build.0 = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyDebug|x86.ActiveCfg = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyDebug|x86.Build.0 = Debug|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyRelease|ARM64.ActiveCfg = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyRelease|ARM64.Build.0 = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyRelease|x64.ActiveCfg = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyRelease|x64.Build.0 = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyRelease|x86.ActiveCfg = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.NativeOnlyRelease|x86.Build.0 = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Release|ARM64.ActiveCfg = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Release|ARM64.Build.0 = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Release|x64.ActiveCfg = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Release|x64.Build.0 = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Release|x86.ActiveCfg = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.Release|x86.Build.0 = Release|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 - {89A12D43-9B91-3960-A6BF-E506122C207A}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Debug|ARM64.ActiveCfg = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Debug|ARM64.Build.0 = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Debug|x64.ActiveCfg = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Debug|x64.Build.0 = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Debug|x86.ActiveCfg = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Debug|x86.Build.0 = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.FuzzerDebug|ARM64.ActiveCfg = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.FuzzerDebug|ARM64.Build.0 = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.FuzzerDebug|x64.ActiveCfg = FuzzerDebug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.FuzzerDebug|x64.Build.0 = FuzzerDebug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.FuzzerDebug|x86.ActiveCfg = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.FuzzerDebug|x86.Build.0 = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.MinSizeRel|ARM64.ActiveCfg = MinSizeRel|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.MinSizeRel|ARM64.Build.0 = MinSizeRel|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.MinSizeRel|x64.Build.0 = MinSizeRel|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.MinSizeRel|x86.Build.0 = MinSizeRel|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyDebug|ARM64.ActiveCfg = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyDebug|ARM64.Build.0 = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyDebug|x64.ActiveCfg = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyDebug|x64.Build.0 = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyDebug|x86.ActiveCfg = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyDebug|x86.Build.0 = Debug|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyRelease|ARM64.ActiveCfg = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyRelease|ARM64.Build.0 = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyRelease|x64.ActiveCfg = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyRelease|x64.Build.0 = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyRelease|x86.ActiveCfg = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.NativeOnlyRelease|x86.Build.0 = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Release|ARM64.ActiveCfg = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Release|ARM64.Build.0 = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Release|x64.ActiveCfg = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Release|x64.Build.0 = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Release|x86.ActiveCfg = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.Release|x86.Build.0 = Release|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64 + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|x64 {1937DB41-F3EB-4955-A636-6386DCB394F6}.Debug|ARM64.ActiveCfg = Debug|x64 {1937DB41-F3EB-4955-A636-6386DCB394F6}.Debug|ARM64.Build.0 = Debug|x64 {1937DB41-F3EB-4955-A636-6386DCB394F6}.Debug|x64.ActiveCfg = Debug|x64 @@ -3125,6 +3127,48 @@ Global {6D365515-DE92-4CEB-AB3D-5608719A8886}.RelWithDebInfo|x64.Build.0 = Release|x64 {6D365515-DE92-4CEB-AB3D-5608719A8886}.RelWithDebInfo|x86.ActiveCfg = Release|x64 {6D365515-DE92-4CEB-AB3D-5608719A8886}.RelWithDebInfo|x86.Build.0 = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Debug|ARM64.ActiveCfg = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Debug|ARM64.Build.0 = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Debug|x64.ActiveCfg = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Debug|x64.Build.0 = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Debug|x86.ActiveCfg = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Debug|x86.Build.0 = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.FuzzerDebug|ARM64.ActiveCfg = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.FuzzerDebug|ARM64.Build.0 = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.FuzzerDebug|x64.ActiveCfg = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.FuzzerDebug|x64.Build.0 = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.FuzzerDebug|x86.ActiveCfg = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.FuzzerDebug|x86.Build.0 = Debug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.MinSizeRel|ARM64.ActiveCfg = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.MinSizeRel|ARM64.Build.0 = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.MinSizeRel|x64.ActiveCfg = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.MinSizeRel|x64.Build.0 = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.MinSizeRel|x86.ActiveCfg = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.MinSizeRel|x86.Build.0 = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyDebug|ARM64.ActiveCfg = NativeOnlyDebug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyDebug|ARM64.Build.0 = NativeOnlyDebug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyDebug|x64.ActiveCfg = NativeOnlyDebug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyDebug|x64.Build.0 = NativeOnlyDebug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyDebug|x86.ActiveCfg = NativeOnlyDebug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyDebug|x86.Build.0 = NativeOnlyDebug|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyRelease|ARM64.ActiveCfg = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyRelease|ARM64.Build.0 = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyRelease|x64.ActiveCfg = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyRelease|x64.Build.0 = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyRelease|x86.ActiveCfg = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.NativeOnlyRelease|x86.Build.0 = NativeOnlyRelease|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Release|ARM64.ActiveCfg = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Release|ARM64.Build.0 = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Release|x64.ActiveCfg = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Release|x64.Build.0 = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Release|x86.ActiveCfg = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.Release|x86.Build.0 = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.RelWithDebInfo|ARM64.ActiveCfg = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.RelWithDebInfo|ARM64.Build.0 = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.RelWithDebInfo|x64.ActiveCfg = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.RelWithDebInfo|x64.Build.0 = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.RelWithDebInfo|x86.ActiveCfg = Release|x64 + {3DBF8A96-3883-448A-8BD3-B8C913A27F09}.RelWithDebInfo|x86.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -3190,7 +3234,7 @@ Global {4F082524-9496-44FA-8CBA-4BC0BDC62568} = {492C9B22-9237-4996-9E33-CA14D3533616} {AA933B9F-B5D8-4AA8-AC18-98FE1A161E8A} = {69CDB6A1-434D-4BC9-9BFF-D12DF7EDBB6B} {030A7AC6-14DC-45CF-AF34-891057AB1402} = {69CDB6A1-434D-4BC9-9BFF-D12DF7EDBB6B} - {89A12D43-9B91-3960-A6BF-E506122C207A} = {69CDB6A1-434D-4BC9-9BFF-D12DF7EDBB6B} + {018D6472-F71C-34B5-BB9B-6BC2A506DB5E} = {69CDB6A1-434D-4BC9-9BFF-D12DF7EDBB6B} {1937DB41-F3EB-4955-A636-6386DCB394F6} = {69CDB6A1-434D-4BC9-9BFF-D12DF7EDBB6B} {1FDAD2FD-EBD8-462A-B285-ED5174E55079} = {97D3096A-20FB-4ACB-A038-88E652FE61E3} {9388DD45-7941-45D7-B4FF-BC00F550AF17} = {69CDB6A1-434D-4BC9-9BFF-D12DF7EDBB6B} @@ -3202,6 +3246,7 @@ Global {984080A6-5890-4ADE-BF8C-DC78EBAB0E8B} = {1A0E5E22-3CAD-412A-9268-F561A5462C77} {C8D46543-5AE5-4E66-B9CE-8B84588B1C9E} = {984080A6-5890-4ADE-BF8C-DC78EBAB0E8B} {6D365515-DE92-4CEB-AB3D-5608719A8886} = {492C9B22-9237-4996-9E33-CA14D3533616} + {3DBF8A96-3883-448A-8BD3-B8C913A27F09} = {B09749EC-3D14-414B-BA9B-CD20E218DC84} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3D5F862D-74C6-4357-9F95-0B152E33B7B8} diff --git a/external/usersim b/external/usersim index 01ae6b8154..c0e6be1630 160000 --- a/external/usersim +++ b/external/usersim @@ -1 +1 @@ -Subproject commit 01ae6b81548fb5e1fc24dbfd1789b94d7adba41e +Subproject commit c0e6be1630ce72e9e6f10783e25bcb590119f4e5 diff --git a/include/ebpf_nethooks.h b/include/ebpf_nethooks.h index e87ff775f6..3f1ba7e83c 100644 --- a/include/ebpf_nethooks.h +++ b/include/ebpf_nethooks.h @@ -265,6 +265,39 @@ typedef struct _bpf_sock_ops typedef int sock_ops_hook_t(bpf_sock_ops_t* context); +typedef enum _process_operation +{ + PROCESS_OPERATION_CREATE, ///< Process creation. + PROCESS_OPERATION_DELETE, ///< Process deletion. +} process_operation_t; + +typedef struct _process_md +{ + uint8_t* command_start; ///< Pointer to start of the command line. + uint8_t* command_end; ///< Pointer to end of the command line. + uint64_t process_id; ///< Process ID. + uint64_t parent_process_id; ///< Parent process ID. + uint64_t creating_process_id; ///< Creating process ID. + uint64_t creating_thread_id; ///< Creating thread ID. + process_operation_t operation; ///< Operation to do. +} process_md_t; + +/* + * @brief Handle process creation and deletion. + * + * Program type: \ref EBPF_PROGRAM_TYPE_PROCESS + * + * Attach type(s): + * \ref EBPF_ATTACH_TYPE_PROCESS + * + * @param[in] context \ref process_md_t + * @return STATUS_SUCCESS to permit the operation, or a failure NTSTATUS value to deny the operation. + * Value of STATUS_SUCCESS is 0x0. + * For PROCESS_OPERATION_DELETE operation, the return value is ignored. + */ +typedef int +process_hook_t(process_md_t* context); + #ifdef _MSC_VER #pragma warning(pop) #endif diff --git a/include/ebpf_program_attach_type_guids.h b/include/ebpf_program_attach_type_guids.h index b0cd7fa2be..f99c6657bd 100644 --- a/include/ebpf_program_attach_type_guids.h +++ b/include/ebpf_program_attach_type_guids.h @@ -85,6 +85,13 @@ extern "C" __declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_XDP_TEST = { 0x0dccc15d, 0xa5f9, 0x4dc1, {0xac, 0x79, 0xfa, 0x25, 0xee, 0xf2, 0x15, 0xc3}}; + /** @brief Attach type for handling process creation and destruction events. + * + * Program type: \ref EBPF_ATTACH_TYPE_PROCESS + */ + __declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_PROCESS = { + 0x66e20687, 0x9805, 0x4458, {0xa0, 0xdb, 0x38, 0xe2, 0x20, 0xd3, 0x16, 0x85}}; + // // Program Types. // @@ -177,6 +184,21 @@ extern "C" */ __declspec(selectany) ebpf_program_type_t EBPF_PROGRAM_TYPE_XDP_TEST = EBPF_PROGRAM_TYPE_XDP_TEST_GUID; +#define EBPF_PROGRAM_TYPE_PROCESS_GUID \ + { \ + 0x22ea7b37, 0x1043, 0x4d0d, { 0xb6, 0x0d, 0xca, 0xfa, 0x1c, 0x7b, 0x63, 0x8e } \ + } + + /** @brief Program type for handling process creation and destruction events. + * + * eBPF program prototype: \ref process_md_t + * + * Attach type(s): \ref EBPF_ATTACH_TYPE_PRCOESS + * + * Helpers available: see bpf_helpers.h + */ + __declspec(selectany) ebpf_program_type_t EBPF_PROGRAM_TYPE_PROCESS = EBPF_PROGRAM_TYPE_PROCESS_GUID; + #ifdef __cplusplus } #endif diff --git a/include/ebpf_structs.h b/include/ebpf_structs.h index 926921d8ee..1a3663de43 100644 --- a/include/ebpf_structs.h +++ b/include/ebpf_structs.h @@ -218,6 +218,17 @@ enum bpf_prog_type */ BPF_PROG_TYPE_SOCK_OPS, + /** @brief Program type for handling process creation and destruction events. + * + * **eBPF program prototype:** \ref process_md_t + * + * **Attach type(s):** + * \ref BPF_ATTACH_TYPE_PROCESS + * + * **Helpers available:** all helpers defined in bpf_helpers.h + */ + BPF_PROG_TYPE_PROCESS, + /** @brief Program type for handling incoming packets as early as possible. * * **eBPF program prototype:** \ref xdp_hook_t @@ -320,6 +331,12 @@ enum bpf_attach_type */ BPF_XDP_TEST, + /** @brief Attach type for handling process events. + * + * **Program type:** \ref BPF_PROG_TYPE_PROCESS + */ + BPF_ATTACH_TYPE_PROCESS, + __MAX_BPF_ATTACH_TYPE, }; diff --git a/netebpfext/net_ebpf_ext.c b/netebpfext/net_ebpf_ext.c index a403a0d923..4e1dcca417 100644 --- a/netebpfext/net_ebpf_ext.c +++ b/netebpfext/net_ebpf_ext.c @@ -19,6 +19,7 @@ #include "net_ebpf_ext.h" #include "net_ebpf_ext_bind.h" +#include "net_ebpf_ext_process.h" #include "net_ebpf_ext_sock_addr.h" #include "net_ebpf_ext_sock_ops.h" #include "net_ebpf_ext_xdp.h" @@ -34,6 +35,7 @@ static bool _net_ebpf_xdp_providers_registered = false; static bool _net_ebpf_bind_providers_registered = false; static bool _net_ebpf_sock_addr_providers_registered = false; static bool _net_ebpf_sock_ops_providers_registered = false; +static bool _net_ebpf_process_providers_registered = false; static net_ebpf_ext_sublayer_info_t _net_ebpf_ext_sublayers[] = { {&EBPF_DEFAULT_SUBLAYER, L"EBPF Sub-Layer", L"Sub-Layer for use by eBPF callouts", 0, SUBLAYER_WEIGHT_MAXIMUM}, @@ -811,6 +813,17 @@ net_ebpf_ext_register_providers() } _net_ebpf_sock_ops_providers_registered = true; + status = net_ebpf_ext_process_register_providers(); + if (!NT_SUCCESS(status)) { + NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS( + NET_EBPF_EXT_TRACELOG_LEVEL_ERROR, + NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION, + "net_ebpf_ext_process_register_providers failed.", + status); + goto Exit; + } + _net_ebpf_process_providers_registered = true; + Exit: if (!NT_SUCCESS(status)) { net_ebpf_ext_unregister_providers(); @@ -837,4 +850,8 @@ net_ebpf_ext_unregister_providers() net_ebpf_ext_sock_ops_unregister_providers(); _net_ebpf_sock_ops_providers_registered = false; } + if (_net_ebpf_process_providers_registered) { + net_ebpf_ext_process_unregister_providers(); + _net_ebpf_process_providers_registered = false; + } } diff --git a/netebpfext/net_ebpf_ext_process.c b/netebpfext/net_ebpf_ext_process.c new file mode 100644 index 0000000000..57f0553978 --- /dev/null +++ b/netebpfext/net_ebpf_ext_process.c @@ -0,0 +1,367 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +/** + * @file + * @brief This file implements the process program type hook on eBPF for Windows. + */ + +#include "ebpf_shared_framework.h" +#include "net_ebpf_ext_process.h" + +static ebpf_result_t +_ebpf_process_context_create( + _In_reads_bytes_opt_(data_size_in) const uint8_t* data_in, + size_t data_size_in, + _In_reads_bytes_opt_(context_size_in) const uint8_t* context_in, + size_t context_size_in, + _Outptr_ void** context); + +static void +_ebpf_process_context_destroy( + _In_opt_ void* context, + _Out_writes_bytes_to_(*data_size_out, *data_size_out) uint8_t* data_out, + _Inout_ size_t* data_size_out, + _Out_writes_bytes_to_(*context_size_out, *context_size_out) uint8_t* context_out, + _Inout_ size_t* context_size_out); + +void +_ebpf_process_create_process_notify_routine_ex( + _Inout_ PEPROCESS process, _In_ HANDLE process_id, _Inout_opt_ PPS_CREATE_NOTIFY_INFO create_info); + +// +// Process Program Information NPI Provider. +// +static ebpf_program_data_t _ebpf_process_program_data = { + .program_info = &_ebpf_process_program_info, + .context_create = _ebpf_process_context_create, + .context_destroy = _ebpf_process_context_destroy, + .required_irql = PASSIVE_LEVEL, +}; + +static ebpf_extension_data_t _ebpf_process_program_info_provider_data = { + NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_process_program_data), &_ebpf_process_program_data}; + +NPI_MODULEID DECLSPEC_SELECTANY _ebpf_process_program_info_provider_moduleid = {sizeof(NPI_MODULEID), MIT_GUID, {0}}; + +static net_ebpf_extension_program_info_provider_t* _ebpf_process_program_info_provider_context = NULL; + +// +// Process Hook NPI Provider. +// +ebpf_attach_provider_data_t _net_ebpf_process_hook_provider_data; + +ebpf_extension_data_t _net_ebpf_extension_process_hook_provider_data = { + EBPF_ATTACH_PROVIDER_DATA_VERSION, + sizeof(_net_ebpf_process_hook_provider_data), + &_net_ebpf_process_hook_provider_data}; + +NPI_MODULEID DECLSPEC_SELECTANY _ebpf_process_hook_provider_moduleid = {sizeof(NPI_MODULEID), MIT_GUID, {0}}; + +static net_ebpf_extension_hook_provider_t* _ebpf_process_hook_provider_context = NULL; + +EX_PUSH_LOCK _ebpf_process_hook_provider_lock; +BOOL _ebpf_process_hook_provider_registered = FALSE; +uint64_t _ebpf_process_hook_provider_registration_count = 0; + +// +// Client attach/detach handler routines. +// + +static ebpf_result_t +_net_ebpf_extension_process_on_client_attach( + _In_ const net_ebpf_extension_hook_client_t* attaching_client, + _In_ const net_ebpf_extension_hook_provider_t* provider_context) +{ + ebpf_result_t result = EBPF_SUCCESS; + bool push_lock_acquired = false; + + NET_EBPF_EXT_LOG_ENTRY(); + + UNREFERENCED_PARAMETER(attaching_client); + UNREFERENCED_PARAMETER(provider_context); + + ExAcquirePushLockExclusive(&_ebpf_process_hook_provider_lock); + + push_lock_acquired = true; + + if (!_ebpf_process_hook_provider_registered) { + // Register the process create notify routine. + NTSTATUS status = PsSetCreateProcessNotifyRoutineEx(_ebpf_process_create_process_notify_routine_ex, FALSE); + if (!NT_SUCCESS(status)) { + NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS( + NET_EBPF_EXT_TRACELOG_LEVEL_ERROR, + NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, + "PsSetCreateProcessNotifyRoutineEx failed", + status); + result = EBPF_OPERATION_NOT_SUPPORTED; + goto Exit; + } + _ebpf_process_hook_provider_registered = TRUE; + } + + _ebpf_process_hook_provider_registration_count++; + +Exit: + if (push_lock_acquired) { + ExReleasePushLockExclusive(&_ebpf_process_hook_provider_lock); + } + + NET_EBPF_EXT_RETURN_RESULT(result); +} + +static void +_net_ebpf_extension_process_on_client_detach(_In_ const net_ebpf_extension_hook_client_t* detaching_client) +{ + ebpf_result_t result = EBPF_SUCCESS; + + NET_EBPF_EXT_LOG_ENTRY(); + + UNREFERENCED_PARAMETER(detaching_client); + + // Unregister the process create notify routine. + ExAcquirePushLockExclusive(&_ebpf_process_hook_provider_lock); + + _ebpf_process_hook_provider_registration_count--; + + if (_ebpf_process_hook_provider_registered && _ebpf_process_hook_provider_registration_count == 0) { + NTSTATUS status = PsSetCreateProcessNotifyRoutineEx(_ebpf_process_create_process_notify_routine_ex, TRUE); + if (!NT_SUCCESS(status)) { + NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS( + NET_EBPF_EXT_TRACELOG_LEVEL_ERROR, + NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, + "PsSetCreateProcessNotifyRoutineEx failed", + status); + result = EBPF_OPERATION_NOT_SUPPORTED; + } + _ebpf_process_hook_provider_registered = FALSE; + } + + ExReleasePushLockExclusive(&_ebpf_process_hook_provider_lock); + + NET_EBPF_EXT_LOG_EXIT(); +} + +// +// NMR Registration Helper Routines. +// + +NTSTATUS +net_ebpf_ext_process_register_providers() +{ + NTSTATUS status = STATUS_SUCCESS; + + NET_EBPF_EXT_LOG_ENTRY(); + + const net_ebpf_extension_program_info_provider_parameters_t program_info_provider_parameters = { + &_ebpf_process_program_info_provider_moduleid, &_ebpf_process_program_info_provider_data}; + const net_ebpf_extension_hook_provider_parameters_t hook_provider_parameters = { + &_ebpf_process_hook_provider_moduleid, &_net_ebpf_extension_process_hook_provider_data}; + + // Set the program type as the provider module id. + _ebpf_process_program_info_provider_moduleid.Guid = EBPF_PROGRAM_TYPE_PROCESS; + status = net_ebpf_extension_program_info_provider_register( + &program_info_provider_parameters, &_ebpf_process_program_info_provider_context); + if (!NT_SUCCESS(status)) { + NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS( + NET_EBPF_EXT_TRACELOG_LEVEL_ERROR, + NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, + "net_ebpf_extension_program_info_provider_register", + status); + goto Exit; + } + + _net_ebpf_process_hook_provider_data.supported_program_type = EBPF_PROGRAM_TYPE_PROCESS; + // Set the attach type as the provider module id. + _ebpf_process_hook_provider_moduleid.Guid = EBPF_ATTACH_TYPE_PROCESS; + _net_ebpf_process_hook_provider_data.bpf_attach_type = BPF_ATTACH_TYPE_PROCESS; + _net_ebpf_process_hook_provider_data.link_type = BPF_LINK_TYPE_PLAIN; + status = net_ebpf_extension_hook_provider_register( + &hook_provider_parameters, + _net_ebpf_extension_process_on_client_attach, + _net_ebpf_extension_process_on_client_detach, + NULL, + &_ebpf_process_hook_provider_context); + if (status != EBPF_SUCCESS) { + NET_EBPF_EXT_LOG_MESSAGE_NTSTATUS( + NET_EBPF_EXT_TRACELOG_LEVEL_ERROR, + NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, + "net_ebpf_extension_hook_provider_register", + status); + goto Exit; + } + +Exit: + if (!NT_SUCCESS(status)) { + net_ebpf_ext_process_unregister_providers(); + } + NET_EBPF_EXT_RETURN_NTSTATUS(status); +} + +void +net_ebpf_ext_process_unregister_providers() +{ + if (_ebpf_process_hook_provider_context) { + net_ebpf_extension_hook_provider_unregister(_ebpf_process_hook_provider_context); + _ebpf_process_hook_provider_context = NULL; + } + if (_ebpf_process_program_info_provider_context) { + net_ebpf_extension_program_info_provider_unregister(_ebpf_process_program_info_provider_context); + _ebpf_process_program_info_provider_context = NULL; + } +} + +static ebpf_result_t +_ebpf_process_context_create( + _In_reads_bytes_opt_(data_size_in) const uint8_t* data_in, + size_t data_size_in, + _In_reads_bytes_opt_(context_size_in) const uint8_t* context_in, + size_t context_size_in, + _Outptr_ void** context) +{ + NET_EBPF_EXT_LOG_ENTRY(); + ebpf_result_t result; + process_md_t* process_context = NULL; + + *context = NULL; + + if (context_in == NULL || context_size_in < sizeof(process_md_t)) { + NET_EBPF_EXT_LOG_MESSAGE( + NET_EBPF_EXT_TRACELOG_LEVEL_ERROR, NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, "Context is required"); + result = EBPF_INVALID_ARGUMENT; + goto Exit; + } + + process_context = + (process_md_t*)ExAllocatePoolUninitialized(NonPagedPoolNx, sizeof(process_md_t), NET_EBPF_EXTENSION_POOL_TAG); + NET_EBPF_EXT_BAIL_ON_ALLOC_FAILURE_RESULT( + NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, process_context, "process_context", result); + + // Copy the context from the caller. + memcpy(process_context, context_in, sizeof(process_md_t)); + + // Replace the process_id_start and process_id_end with pointers to data_in. + process_context->command_start = (uint8_t*)data_in; + process_context->command_end = (uint8_t*)data_in + data_size_in; + + *context = process_context; + process_context = NULL; + result = EBPF_SUCCESS; + +Exit: + if (process_context) { + ExFreePool(process_context); + process_context = NULL; + } + NET_EBPF_EXT_RETURN_RESULT(result); +} + +static void +_ebpf_process_context_destroy( + _In_opt_ void* context, + _Out_writes_bytes_to_(*data_size_out, *data_size_out) uint8_t* data_out, + _Inout_ size_t* data_size_out, + _Out_writes_bytes_to_(*context_size_out, *context_size_out) uint8_t* context_out, + _Inout_ size_t* context_size_out) +{ + NET_EBPF_EXT_LOG_ENTRY(); + + process_md_t* process_context = (process_md_t*)context; + process_md_t* process_context_out = (process_md_t*)context_out; + + if (!process_context) { + goto Exit; + } + + if (context_out != NULL && *context_size_out >= sizeof(process_md_t)) { + // Copy the context to the caller. + memcpy(process_context_out, process_context, sizeof(process_md_t)); + + // Zero out the command_start and command_end. + process_context_out->command_start = 0; + process_context_out->command_end = 0; + *context_size_out = sizeof(process_md_t); + } else { + *context_size_out = 0; + } + + // Copy the command to the data_out. + if (data_out != NULL && *data_size_out >= (size_t)(process_context->command_end - process_context->command_start)) { + memcpy(data_out, process_context->command_start, process_context->command_end - process_context->command_start); + *data_size_out = process_context->command_end - process_context->command_start; + } else { + *data_size_out = 0; + } + + ExFreePool(process_context); + +Exit: + NET_EBPF_EXT_LOG_EXIT(); +} + +typedef struct _process_notify_context +{ + process_md_t process_md; + PEPROCESS process; + PPS_CREATE_NOTIFY_INFO create_info; +} process_notify_context_t; + +void +_ebpf_process_create_process_notify_routine_ex( + _Inout_ PEPROCESS process, _In_ HANDLE process_id, _Inout_opt_ PPS_CREATE_NOTIFY_INFO create_info) +{ + process_notify_context_t process_notify_context = { + .process_md = {0}, .process = process, .create_info = create_info}; + + NET_EBPF_EXT_LOG_ENTRY(); + + if (create_info != NULL && create_info->CommandLine != NULL) { + process_notify_context.process_md.command_start = (uint8_t*)create_info->CommandLine->Buffer; + process_notify_context.process_md.command_end = + (uint8_t*)create_info->CommandLine->Buffer + create_info->CommandLine->Length; + } + + process_notify_context.process_md.operation = + (create_info != NULL) ? PROCESS_OPERATION_CREATE : PROCESS_OPERATION_DELETE; + process_notify_context.process_md.process_id = (uint64_t)process_id; + process_notify_context.process_md.parent_process_id = + (create_info != NULL) ? (uint64_t)create_info->ParentProcessId : 0; + process_notify_context.process_md.creating_process_id = + (create_info != NULL) ? (uint64_t)create_info->CreatingThreadId.UniqueProcess : 0; + process_notify_context.process_md.creating_thread_id = + (create_info != NULL) ? (uint64_t)create_info->CreatingThreadId.UniqueThread : 0; + + // For each attached client call the process hook. + ebpf_result_t result; + net_ebpf_extension_hook_client_t* client_context = + net_ebpf_extension_hook_get_next_attached_client(_ebpf_process_hook_provider_context, NULL); + while (client_context != NULL) { + NTSTATUS status = 0; + if (net_ebpf_extension_hook_client_enter_rundown(client_context)) { + result = net_ebpf_extension_hook_invoke_program( + client_context, &process_notify_context.process_md, (uint32_t*)&status); + if (result != EBPF_SUCCESS) { + NET_EBPF_EXT_LOG_MESSAGE( + NET_EBPF_EXT_TRACELOG_LEVEL_ERROR, + NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, + "net_ebpf_extension_hook_invoke_program failed"); + } + net_ebpf_extension_hook_client_leave_rundown(client_context); + } else { + NET_EBPF_EXT_LOG_MESSAGE( + NET_EBPF_EXT_TRACELOG_LEVEL_ERROR, + NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, + "net_ebpf_extension_hook_client_enter_rundown failed"); + } + // If the client returns a non-zero value, stop calling the other clients. + if (!NT_SUCCESS(status) && create_info) { + create_info->CreationStatus = status; + break; + } + + client_context = + net_ebpf_extension_hook_get_next_attached_client(_ebpf_process_hook_provider_context, client_context); + } + + NET_EBPF_EXT_LOG_EXIT(); +} diff --git a/netebpfext/net_ebpf_ext_process.h b/netebpfext/net_ebpf_ext_process.h new file mode 100644 index 0000000000..2016f02ff1 --- /dev/null +++ b/netebpfext/net_ebpf_ext_process.h @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +#pragma once + +#include "net_ebpf_ext.h" + +/** + * @brief Unregister PROCESS NPI providers. + * + */ +void +net_ebpf_ext_process_unregister_providers(); + +/** + * @brief Register PROCESS NPI providers. + * + * @retval STATUS_SUCCESS Operation succeeded. + * @retval STATUS_UNSUCCESSFUL Operation failed. + */ +NTSTATUS +net_ebpf_ext_process_register_providers(); diff --git a/netebpfext/net_ebpf_ext_program_info.h b/netebpfext/net_ebpf_ext_program_info.h index b3aeccb204..b26b1c125e 100644 --- a/netebpfext/net_ebpf_ext_program_info.h +++ b/netebpfext/net_ebpf_ext_program_info.h @@ -121,3 +121,16 @@ static const ebpf_program_section_info_t _ebpf_sock_ops_section_info[] = { &EBPF_ATTACH_TYPE_CGROUP_SOCK_OPS, BPF_PROG_TYPE_SOCK_OPS, BPF_CGROUP_SOCK_OPS}}; + +static const ebpf_context_descriptor_t _ebpf_process_context_descriptor = { + sizeof(process_md_t), EBPF_OFFSET_OF(process_md_t, command_start), EBPF_OFFSET_OF(process_md_t, command_end), -1}; + +static const ebpf_program_info_t _ebpf_process_program_info = { + {"process", &_ebpf_process_context_descriptor, EBPF_PROGRAM_TYPE_PROCESS_GUID, BPF_PROG_TYPE_PROCESS}, 0, NULL}; + +static const ebpf_program_section_info_t _ebpf_process_section_info[] = { + {L"process", + &EBPF_PROGRAM_TYPE_PROCESS, + &EBPF_ATTACH_TYPE_PROCESS, + BPF_PROG_TYPE_PROCESS, + BPF_ATTACH_TYPE_PROCESS}}; diff --git a/netebpfext/net_ebpf_ext_tracelog.c b/netebpfext/net_ebpf_ext_tracelog.c index ad492866e5..f3d1d1ae12 100644 --- a/netebpfext/net_ebpf_ext_tracelog.c +++ b/netebpfext/net_ebpf_ext_tracelog.c @@ -48,6 +48,7 @@ net_ebpf_ext_trace_terminate() #define KEYWORD_BASE NET_EBPF_EXT_TRACELOG_KEYWORD_BASE #define KEYWORD_BIND NET_EBPF_EXT_TRACELOG_KEYWORD_BIND #define KEYWORD_EXT NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION +#define KEYWORD_PROCESS NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS #define KEYWORD_SOCK_ADDR NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_ADDR #define KEYWORD_SOCK_OPS NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS #define KEYWORD_XDP NET_EBPF_EXT_TRACELOG_KEYWORD_XDP @@ -55,6 +56,7 @@ net_ebpf_ext_trace_terminate() #define CASE_BASE case _NET_EBPF_EXT_TRACELOG_KEYWORD_BASE #define CASE_BIND case _NET_EBPF_EXT_TRACELOG_KEYWORD_BIND #define CASE_EXT case _NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION +#define CASE_PROCESS case _NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS #define CASE_SOCK_ADDR case _NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_ADDR #define CASE_SOCK_OPS case _NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS #define CASE_XDP case _NET_EBPF_EXT_TRACELOG_KEYWORD_XDP diff --git a/netebpfext/net_ebpf_ext_tracelog.h b/netebpfext/net_ebpf_ext_tracelog.h index 3ef95c2cd5..28e7805d9c 100644 --- a/netebpfext/net_ebpf_ext_tracelog.h +++ b/netebpfext/net_ebpf_ext_tracelog.h @@ -25,6 +25,7 @@ net_ebpf_ext_trace_terminate(); #define NET_EBPF_EXT_TRACELOG_KEYWORD_BIND 0x10 #define NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_ADDR 0x20 #define NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS 0x40 +#define NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS 0x80 #define NET_EBPF_EXT_TRACELOG_LEVEL_LOG_ALWAYS WINEVENT_LEVEL_LOG_ALWAYS #define NET_EBPF_EXT_TRACELOG_LEVEL_CRITICAL WINEVENT_LEVEL_CRITICAL @@ -40,7 +41,8 @@ typedef enum _net_ebpf_ext_tracelog_keyword _NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION, _NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_ADDR, _NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_OPS, - _NET_EBPF_EXT_TRACELOG_KEYWORD_XDP + _NET_EBPF_EXT_TRACELOG_KEYWORD_XDP, + _NET_EBPF_EXT_TRACELOG_KEYWORD_PROCESS, } net_ebpf_ext_tracelog_keyword_t; typedef enum _net_ebpf_ext_tracelog_level diff --git a/netebpfext/sys/netebpfext.vcxproj b/netebpfext/sys/netebpfext.vcxproj index 31c238b246..e8217b0b60 100644 --- a/netebpfext/sys/netebpfext.vcxproj +++ b/netebpfext/sys/netebpfext.vcxproj @@ -132,6 +132,7 @@ %(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib;$(DDK_LIB_PATH)\netio.lib $(OutDir);$(SolutionDir)$(Platform)\$(ConfigurationName)\;%(AdditionalLibraryDirectories) + /INTEGRITYCHECK %(AdditionalOptions) SHA256 @@ -154,6 +155,7 @@ %(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib;$(DDK_LIB_PATH)\netio.lib $(OutDir);$(SolutionDir)$(Platform)\$(ConfigurationName)\;%(AdditionalLibraryDirectories) + /INTEGRITYCHECK %(AdditionalOptions) SHA256 @@ -175,6 +177,7 @@ %(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib;$(DDK_LIB_PATH)\netio.lib $(OutDir);$(SolutionDir)$(Platform)\$(ConfigurationName)\;%(AdditionalLibraryDirectories) + /INTEGRITYCHECK %(AdditionalOptions) SHA256 @@ -196,6 +199,7 @@ %(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib;$(DDK_LIB_PATH)\netio.lib $(OutDir);$(SolutionDir)$(Platform)\$(ConfigurationName)\;%(AdditionalLibraryDirectories) + /INTEGRITYCHECK %(AdditionalOptions) SHA256 @@ -206,6 +210,7 @@ + @@ -226,6 +231,7 @@ + diff --git a/netebpfext/sys/netebpfext.vcxproj.filters b/netebpfext/sys/netebpfext.vcxproj.filters index d53c1d4ea3..79b3e26eed 100644 --- a/netebpfext/sys/netebpfext.vcxproj.filters +++ b/netebpfext/sys/netebpfext.vcxproj.filters @@ -53,6 +53,9 @@ Source Files + + Source Files + @@ -98,5 +101,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/netebpfext/user/netebpfext_user.vcxproj b/netebpfext/user/netebpfext_user.vcxproj index 93efa22eed..16add327e5 100644 --- a/netebpfext/user/netebpfext_user.vcxproj +++ b/netebpfext/user/netebpfext_user.vcxproj @@ -137,6 +137,7 @@ + @@ -147,6 +148,7 @@ + diff --git a/netebpfext/user/netebpfext_user.vcxproj.filters b/netebpfext/user/netebpfext_user.vcxproj.filters index 1900da0613..076abf6eed 100644 --- a/netebpfext/user/netebpfext_user.vcxproj.filters +++ b/netebpfext/user/netebpfext_user.vcxproj.filters @@ -46,6 +46,9 @@ Source Files + + Source Files + @@ -78,5 +81,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/tests/end_to_end/helpers.h b/tests/end_to_end/helpers.h index f8ef633754..e914bc3b6a 100644 --- a/tests/end_to_end/helpers.h +++ b/tests/end_to_end/helpers.h @@ -695,6 +695,12 @@ static ebpf_extension_data_t _test_ebpf_sample_extension_program_info_provider_d sizeof(_test_ebpf_sample_extension_program_data), &_test_ebpf_sample_extension_program_data}; +// Process. +static ebpf_program_data_t _ebpf_process_program_data = {&_ebpf_process_program_info, NULL}; + +static ebpf_extension_data_t _ebpf_process_program_info_provider_data = { + TEST_NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_process_program_data), &_ebpf_process_program_data}; + typedef class _program_info_provider { public: @@ -722,6 +728,8 @@ typedef class _program_info_provider provider_data = &_ebpf_sock_ops_program_info_provider_data; } else if (program_type == EBPF_PROGRAM_TYPE_SAMPLE) { provider_data = &_test_ebpf_sample_extension_program_info_provider_data; + } else if (program_type == EBPF_PROGRAM_TYPE_PROCESS) { + provider_data = &_ebpf_process_program_info_provider_data; } else { // Unsupported program type. return EBPF_INVALID_ARGUMENT; diff --git a/tests/netebpfext_unit/netebpfext_unit.cpp b/tests/netebpfext_unit/netebpfext_unit.cpp index e748d112fe..61f54c5d1d 100644 --- a/tests/netebpfext_unit/netebpfext_unit.cpp +++ b/tests/netebpfext_unit/netebpfext_unit.cpp @@ -48,8 +48,10 @@ TEST_CASE("query program info", "[netebpfext]") EBPF_PROGRAM_TYPE_CGROUP_SOCK_ADDR, EBPF_PROGRAM_TYPE_SOCK_OPS, EBPF_PROGRAM_TYPE_BIND, - EBPF_PROGRAM_TYPE_XDP_TEST}; - std::vector expected_program_names = {"sock_addr", "sockops", "bind", "xdp_test"}; + EBPF_PROGRAM_TYPE_XDP_TEST, + EBPF_PROGRAM_TYPE_PROCESS, + }; + std::vector expected_program_names = {"sock_addr", "sockops", "bind", "xdp_test", "process"}; auto guid_less = [](const GUID& lhs, const GUID& rhs) { return memcmp(&lhs, &rhs, sizeof(lhs)) < 0; }; @@ -883,3 +885,81 @@ TEST_CASE("sock_ops_context", "[netebpfext]") REQUIRE(output_context.interface_luid == 0x1234567890abcdee); } #pragma endregion sock_ops + +#pragma region process + +typedef struct test_process_client_context_t +{ + netebpfext_helper_base_client_context_t base; + process_md_t process_context; +} test_process_client_context_t; + +_Must_inspect_result_ ebpf_result_t +netebpfext_unit_invoke_process_program( + _In_ const void* client_process_context, _In_ const void* context, _Out_ uint32_t* result) +{ + process_md_t* process_context = (process_md_t*)context; + test_process_client_context_t* client_context = (test_process_client_context_t*)client_process_context; + + client_context->process_context = *process_context; + *result = STATUS_ACCESS_DENIED; + return EBPF_SUCCESS; +} + +TEST_CASE("process_invoke", "[netebpfext]") +{ + ebpf_extension_data_t npi_specific_characteristics = {}; + test_process_client_context_t client_context = {}; + + netebpf_ext_helper_t helper( + &npi_specific_characteristics, + (_ebpf_extension_dispatch_function)netebpfext_unit_invoke_process_program, + (netebpfext_helper_base_client_context_t*)&client_context); + + // Test process creation. + std::wstring process_name = L"notepad.exe"; + std::wstring command_line = L"notepad.exe foo.txt"; + UNICODE_STRING process_name_unicode = {}; + UNICODE_STRING command_line_unicode = {}; + + PS_CREATE_NOTIFY_INFO create_info = {}; + create_info.CommandLine = &command_line_unicode; + create_info.ImageFileName = &process_name_unicode; + create_info.ParentProcessId = (HANDLE)4; + create_info.CreatingThreadId.UniqueProcess = (HANDLE)5; + create_info.CreatingThreadId.UniqueThread = (HANDLE)6; + create_info.CreationStatus = STATUS_SUCCESS; + + RtlInitUnicodeString(&process_name_unicode, process_name.c_str()); + RtlInitUnicodeString(&command_line_unicode, command_line.c_str()); + + struct + { + uint64_t some_value; + } fake_eprocess = {}; + + usersime_invoke_process_creation_notify_routine( + reinterpret_cast(&fake_eprocess), (HANDLE)1, &create_info); + + std::wstring test_command_line = std::wstring( + reinterpret_cast(client_context.process_context.command_start), + reinterpret_cast(client_context.process_context.command_end)); + + REQUIRE(test_command_line == command_line); + + REQUIRE(client_context.process_context.process_id == 1); + REQUIRE((HANDLE)client_context.process_context.parent_process_id == create_info.ParentProcessId); + REQUIRE((HANDLE)client_context.process_context.creating_process_id == create_info.CreatingThreadId.UniqueProcess); + REQUIRE((HANDLE)client_context.process_context.creating_thread_id == create_info.CreatingThreadId.UniqueThread); + REQUIRE(create_info.CreationStatus == STATUS_ACCESS_DENIED); + REQUIRE(client_context.process_context.operation == PROCESS_OPERATION_CREATE); + + // Test process termination. + // Just verify that it doesn't crash. + usersime_invoke_process_creation_notify_routine(reinterpret_cast(&fake_eprocess), (HANDLE)1, nullptr); + + REQUIRE(client_context.process_context.process_id == 1); + REQUIRE(client_context.process_context.operation == PROCESS_OPERATION_DELETE); +} + +#pragma endregion process \ No newline at end of file diff --git a/tests/sample/process_monitor.c b/tests/sample/process_monitor.c new file mode 100644 index 0000000000..26abb7dfdc --- /dev/null +++ b/tests/sample/process_monitor.c @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +// clang -O2 -Werror -c bindmonitor.c -o bindmonitor_jit.o +// +// For bpf code: clang -target bpf -O2 -Werror -c bindmonitor.c -o bindmonitor.o +// this passes the checker + +// Whenever this sample program changes, bpf2c_tests will fail unless the +// expected files in tests\bpf2c_tests\expected are updated. The following +// script can be used to regenerate the expected files: +// generate_expected_bpf2c_output.ps1 +// +// Usage: +// .\scripts\generate_expected_bpf2c_output.ps1 +// Example: +// .\scripts\generate_expected_bpf2c_output.ps1 .\x64\Debug\ + +#include "bpf_helpers.h" +#include "ebpf_nethooks.h" + +typedef struct +{ + uint64_t parent_process_id; + uint8_t command_line[256]; +} proces_entry_t; + +typedef struct +{ + uint64_t process_id; + proces_entry_t entry; +} process_create_event_t; + +typedef struct +{ + uint64_t process_id; +} process_delete_event_t; + +// Map for running processes. +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, uint64_t); + __type(value, proces_entry_t); + __uint(max_entries, 1024); +} process_map SEC(".maps"); + +// Ringbuffer for process events. +struct +{ + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 1024 * 64); +} process_ringbuf SEC(".maps"); + +// For debug builds, limit the number of iterations in the loop to 16 to prevent the verifier from +// running for too long. For release builds, limit the number of iterations to 256. +#if defined(NDEBUG) +#define BOUNDED_MEMCPY_LIMIT 256 +#else +#define BOUNDED_MEMCPY_LIMIT 16 +#endif + +__attribute__((always_inline)) +// Copy the first 'source_size' bytes from 'source' to 'destination' and bound the copy to 'destination_size' bytes. +void +bounded_memcpy(uint8_t* destination, const uint8_t* source, uint32_t destination_size, uint32_t source_size) +{ +// Prevail verifier doesn't correctly compute the number of iterations in the loop. +// Unroll the loop to avoid the verifier error. +// Issue: https://github.com/vbpf/ebpf-verifier/issues/441 +#pragma unroll + for (uint32_t index = 0; index < BOUNDED_MEMCPY_LIMIT; index++) { + if (index < destination_size && index < source_size) { + destination[index] = source[index]; + } + } +} + +// The following line is optional, but is used to verify +// that the ProcesMonitor prototype is correct or the compiler +// would complain when the function is actually defined below. +process_hook_t ProcesMonitor; + +SEC("process") +int +ProcessMonitor(process_md_t* ctx) +{ + if (ctx->operation == PROCESS_OPERATION_CREATE) { + process_create_event_t create_event; + __builtin_memset(&create_event, 0, sizeof(create_event)); + create_event.entry.parent_process_id = ctx->parent_process_id; + create_event.process_id = ctx->process_id; + uint64_t process_id = ctx->process_id; + + bounded_memcpy( + create_event.entry.command_line, + ctx->command_start, + sizeof(create_event.entry.command_line), + (uint32_t)(ctx->command_end - ctx->command_start)); + + bpf_map_update_elem(&process_map, &process_id, &create_event.entry, BPF_ANY); + bpf_ringbuf_output(&process_ringbuf, &create_event, sizeof(create_event), 0); + } else if (ctx->operation == PROCESS_OPERATION_DELETE) { + process_delete_event_t delete_event = {.process_id = ctx->process_id}; + uint64_t process_id = ctx->process_id; + bpf_map_delete_elem(&process_map, &process_id); + bpf_ringbuf_output(&process_ringbuf, &delete_event, sizeof(delete_event), 0); + } + return 0; +} diff --git a/tests/sample/sample.vcxproj b/tests/sample/sample.vcxproj index 04735a2edd..3246d0f132 100644 --- a/tests/sample/sample.vcxproj +++ b/tests/sample/sample.vcxproj @@ -38,6 +38,21 @@ 10.0 -g -target bpf -O2 -Werror -I../../include -I../../external/bpftool + + $(ClangFlags) -DDEBUG + + + $(ClangFlags) -DDEBUG + + + $(ClangFlags) -DDEBUG + + + $(ClangFlags) -DNDEBUG + + + $(ClangFlags) -DNDEBUG + Application diff --git a/tests/unit/libbpf_test.cpp b/tests/unit/libbpf_test.cpp index 7f656160e3..1f949daa4a 100644 --- a/tests/unit/libbpf_test.cpp +++ b/tests/unit/libbpf_test.cpp @@ -9,6 +9,7 @@ #include "capture_helper.hpp" #include "catch_wrapper.hpp" #include "common_tests.h" +#include "ebpf_nethooks.h" #include "ebpf_platform.h" #include "ebpf_tracelog.h" #include "ebpf_vm_isa.hpp" @@ -3363,4 +3364,72 @@ TEST_CASE("hash_of_map", "[libbpf]") #endif _hash_of_map_initial_value_test(EBPF_EXECUTION_NATIVE); -} \ No newline at end of file +} + +typedef struct +{ + uint64_t parent_process_id; + uint8_t command_line[256]; +} proces_entry_t; + +static void +_process_hook_test(ebpf_execution_type_t execution_type) +{ + _test_helper_end_to_end test_helper; + const char dll_name[] = "process_monitor_um.dll"; + const char obj_name[] = "process_monitor.o"; + test_helper.initialize(); + single_instance_hook_t hook(EBPF_PROGRAM_TYPE_PROCESS, EBPF_ATTACH_TYPE_PROCESS); + REQUIRE(hook.initialize() == EBPF_SUCCESS); + program_info_provider_t sample_program_info; + REQUIRE(sample_program_info.initialize(EBPF_PROGRAM_TYPE_PROCESS) == EBPF_SUCCESS); + + const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? dll_name : obj_name); + struct bpf_object* process_object = bpf_object__open(file_name); + REQUIRE(process_object != nullptr); + + // Load the program(s). + REQUIRE(bpf_object__load(process_object) == 0); + + struct bpf_program* caller = bpf_object__find_program_by_name(process_object, "ProcessMonitor"); + REQUIRE(caller != nullptr); + + struct bpf_map* process_map = bpf_object__find_map_by_name(process_object, "process_map"); + REQUIRE(process_map != nullptr); + + bpf_link_ptr link(bpf_program__attach(caller)); + REQUIRE(link != nullptr); + + // Now run the ebpf program. + process_md_t ctx{0}; + ctx.process_id = 1234; + ctx.operation = PROCESS_OPERATION_CREATE; + ctx.parent_process_id = 5678; + ctx.command_start = (uint8_t*)"test_process"; + ctx.command_end = ctx.command_start + strlen((char*)ctx.command_start); + + uint32_t result; + REQUIRE(hook.fire(&ctx, &result) == EBPF_SUCCESS); + + // Check if the entry was added to the map. + uint64_t key = 1234; + proces_entry_t value; + REQUIRE(bpf_map_lookup_elem(bpf_map__fd(process_map), &key, &value) == 0); + + // Verify the entry. + REQUIRE(value.parent_process_id == 5678); + REQUIRE(strcmp((char*)value.command_line, "test_process") == 0); + + // Test process termination. + ctx.operation = PROCESS_OPERATION_DELETE; + REQUIRE(hook.fire(&ctx, &result) == EBPF_SUCCESS); + + // Check if the entry was removed from the map. + REQUIRE(bpf_map_lookup_elem(bpf_map__fd(process_map), &key, &value) != 0); + + result = bpf_link__destroy(link.release()); + REQUIRE(result == 0); + bpf_object__close(process_object); +} + +DECLARE_ALL_TEST_CASES("process_hook", "[libbf]", _process_hook_test); \ No newline at end of file diff --git a/tools/export_program_info/export_program_info.cpp b/tools/export_program_info/export_program_info.cpp index 4ecb7248d7..3c7d8e6070 100644 --- a/tools/export_program_info/export_program_info.cpp +++ b/tools/export_program_info/export_program_info.cpp @@ -29,6 +29,7 @@ typedef struct _ebpf_program_section_info_with_count static const ebpf_program_info_t* _program_information_array[] = { &_ebpf_bind_program_info, + &_ebpf_process_program_info, &_ebpf_sock_addr_program_info, &_ebpf_sock_ops_program_info, &_mock_xdp_program_info, @@ -40,6 +41,7 @@ ebpf_program_section_info_t _mock_xdp_section_info[] = { static std::vector _section_information = { {&_ebpf_bind_section_info[0], _countof(_ebpf_bind_section_info)}, {&_mock_xdp_section_info[0], _countof(_mock_xdp_section_info)}, + {&_ebpf_process_section_info[0], _countof(_ebpf_process_section_info)}, {&_ebpf_sock_addr_section_info[0], _countof(_ebpf_sock_addr_section_info)}, {&_ebpf_sock_ops_section_info[0], _countof(_ebpf_sock_ops_section_info)}, {&_ebpf_xdp_test_section_info[0], _countof(_ebpf_xdp_test_section_info)}, diff --git a/tools/process_monitor/process_monitor.cpp b/tools/process_monitor/process_monitor.cpp new file mode 100644 index 0000000000..ffb95dce04 --- /dev/null +++ b/tools/process_monitor/process_monitor.cpp @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +// Windows.h needs to be the first include to prevent failures in subsequent headers. +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "ebpfapi.lib") + +extern "C" +{ + int + process_monitor_history_callback(void* ctx, void* data, size_t size); +} + +typedef struct +{ + uint64_t parent_process_id; + uint8_t command_line[256]; +} proces_entry_t; + +typedef struct +{ + uint64_t process_id; + proces_entry_t entry; +} process_create_event_t; + +typedef struct +{ + uint64_t process_id; +} process_delete_event_t; + +int +process_monitor_history_callback(void* ctx, void* data, size_t size) +{ + UNREFERENCED_PARAMETER(ctx); + + switch (size) { + case sizeof(process_create_event_t): { + process_create_event_t* event = (process_create_event_t*)data; + std::wcout << L"Process created: " << event->process_id << L" " + << reinterpret_cast(event->entry.command_line) << std::endl; + break; + } + case sizeof(process_delete_event_t): { + process_delete_event_t* event = (process_delete_event_t*)data; + std::wcout << L"Process deleted: " << event->process_id << std::endl; + break; + } + default: + std::wcout << L"Unknown event size: " << size << std::endl; + break; + } + + return 0; +} + +bool _shutdown = false; +std::condition_variable _wait_for_shutdown; +std::mutex _wait_for_shutdown_mutex; + +int +control_handler(unsigned long control_type) +{ + if (control_type != CTRL_C_EVENT) { + return false; + } + std::unique_lock lock(_wait_for_shutdown_mutex); + _shutdown = true; + _wait_for_shutdown.notify_all(); + return true; +} + +int +main(int argc, char** argv) +{ + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + if (!SetConsoleCtrlHandler(control_handler, true)) { + std::cerr << "SetConsoleCtrlHandler: " << GetLastError() << std::endl; + return 1; + } + + std::cerr << "Press Ctrl-C to shutdown" << std::endl; + + // Load process_monitor.sys BPF program. + struct bpf_object* object = bpf_object__open("process_monitor.sys"); + if (!object) { + std::cerr << "bpf_object__open for process_monitor.sys failed: " << errno << std::endl; + return 1; + } + + if (bpf_object__load(object) < 0) { + std::cerr << "bpf_object__load for process_monitor.sys failed: " << errno << std::endl; + return 1; + } + + auto process_monitor = bpf_object__find_program_by_name(object, "ProcessMonitor"); + if (!process_monitor) { + std::cerr << "bpf_object__find_program_by_name for \"connection_tracker\" failed: " << errno << std::endl; + return 1; + } + + auto process_monitor_link = bpf_program__attach(process_monitor); + if (!process_monitor_link) { + std::cerr << "BPF program process_monitor.sys failed to attach: " << errno << std::endl; + return 1; + } + + // Attach to ring buffer. + bpf_map* map = bpf_object__find_map_by_name(object, "process_ringbuf"); + if (!map) { + std::cerr << "Unable to locate history map: " << errno << std::endl; + return 1; + } + auto ring = ring_buffer__new(bpf_map__fd(map), process_monitor_history_callback, nullptr, nullptr); + if (!ring) { + std::cerr << "Unable to create ring buffer: " << errno << std::endl; + return 1; + } + + // Wait for Ctrl-C. + { + std::unique_lock lock(_wait_for_shutdown_mutex); + _wait_for_shutdown.wait(lock, []() { return _shutdown; }); + } + + // Detach from the attach point. + int link_fd = bpf_link__fd(process_monitor_link); + bpf_link_detach(link_fd); + bpf_link__destroy(process_monitor_link); + + // Close ring buffer. + ring_buffer__free(ring); + + // Free the BPF object. + bpf_object__close(object); + return 0; +} \ No newline at end of file diff --git a/tools/process_monitor/process_monitor.vcxproj b/tools/process_monitor/process_monitor.vcxproj new file mode 100644 index 0000000000..31bbec8187 --- /dev/null +++ b/tools/process_monitor/process_monitor.vcxproj @@ -0,0 +1,148 @@ + + + + + + Debug + x64 + + + NativeOnlyDebug + x64 + + + NativeOnlyRelease + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {3DBF8A96-3883-448A-8BD3-B8C913A27F09} + process_monitor + 10.0 + + + + Application + true + v143 + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + Unicode + + + Application + false + v143 + Unicode + + + + + + + + + + + + + + + + + + + + + false + + + false + + + false + + + false + + + + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)include;$(SolutionDir)external\bpftool;$(SolutionDir)external\ebpf-verifier\src + + + Console + true + + + + + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)include;$(SolutionDir)external\bpftool;$(SolutionDir)external\ebpf-verifier\src + + + Console + true + + + + + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)include;$(SolutionDir)external\bpftool;$(SolutionDir)external\ebpf-verifier\src + + + Console + true + true + true + + + + + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)include;$(SolutionDir)external\bpftool;$(SolutionDir)external\ebpf-verifier\src + + + Console + true + true + true + + + + + + + + {75fe223a-3e45-4b0e-a2e8-04285e52e440} + + + + + + \ No newline at end of file diff --git a/tools/process_monitor/process_monitor.vcxproj.filters b/tools/process_monitor/process_monitor.vcxproj.filters new file mode 100644 index 0000000000..ada4019cd8 --- /dev/null +++ b/tools/process_monitor/process_monitor.vcxproj.filters @@ -0,0 +1,26 @@ + + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file