diff --git a/ebpf/CMakeLists.txt b/ebpf/CMakeLists.txt index 0f2a575..38f6d58 100644 --- a/ebpf/CMakeLists.txt +++ b/ebpf/CMakeLists.txt @@ -51,6 +51,9 @@ function(ebpfCommonEbpf) src/uprobeperfevent.h src/uprobeperfevent.cpp + + include/tob/ebpf/feature_detect.h + src/feature_detect.cpp ) target_include_directories(ebpf PUBLIC include) diff --git a/ebpf/include/tob/ebpf/ebpf_utils.h b/ebpf/include/tob/ebpf/ebpf_utils.h index 4be4b1d..f3bb193 100644 --- a/ebpf/include/tob/ebpf/ebpf_utils.h +++ b/ebpf/include/tob/ebpf/ebpf_utils.h @@ -23,6 +23,9 @@ createPerfEventOutputForCPU(std::size_t processor_index, StringErrorOr loadProgram(const BPFProgram &program, IPerfEvent &perf_event); +StringErrorOr +loadProgram(const BPFProgram &program, + bpf_prog_type program_type = BPF_PROG_TYPE_UNSPEC); StringErrorOr getLinuxKernelVersionCode(); } // namespace tob::ebpf diff --git a/ebpf/include/tob/ebpf/feature_detect.h b/ebpf/include/tob/ebpf/feature_detect.h new file mode 100644 index 0000000..2386c90 --- /dev/null +++ b/ebpf/include/tob/ebpf/feature_detect.h @@ -0,0 +1,20 @@ +/* + Copyright (c) 2019-present, Trail of Bits, Inc. + All rights reserved. + + This source code is licensed in accordance with the terms specified in + the LICENSE file found in the root directory of this source tree. +*/ + +#pragma once + +#include + +namespace tob::ebpf { + +class FeatureDetection { +public: + static bool isHelperImplemented(bpf_func_id id); +}; + +} // namespace tob::ebpf diff --git a/ebpf/src/ebpf_utils.cpp b/ebpf/src/ebpf_utils.cpp index b048b5e..8c8bc35 100644 --- a/ebpf/src/ebpf_utils.cpp +++ b/ebpf/src/ebpf_utils.cpp @@ -332,9 +332,7 @@ createPerfEventOutputForCPU(std::size_t processor_index, StringErrorOr loadProgram(const BPFProgram &program, IPerfEvent &perf_event) { - - bpf_prog_type program_type{}; - std::uint32_t linux_version{}; + bpf_prog_type program_type; switch (perf_event.type()) { case IPerfEvent::Type::Tracepoint: { @@ -347,19 +345,44 @@ StringErrorOr loadProgram(const BPFProgram &program, case IPerfEvent::Type::Uprobe: case IPerfEvent::Type::Uretprobe: { program_type = BPF_PROG_TYPE_KPROBE; + break; + } + + default: { + return StringError::create("Unsupported perf event type"); + } + } + + auto output_exp = loadProgram(program, program_type); + if (!output_exp.succeeded()) { + return output_exp; + } + + if (ioctl(perf_event.fd(), PERF_EVENT_IOC_SET_BPF, output_exp->get()) < 0) { + return StringError::create( + "Failed to attach the BPF program to the perf event. Errno: " + + std::to_string(errno)); + } + + if (ioctl(perf_event.fd(), PERF_EVENT_IOC_ENABLE, 0) < 0) { + return StringError::create("Failed to enable the perf event. Errno: " + + std::to_string(errno)); + } + return output_exp; +} + +StringErrorOr loadProgram(const BPFProgram &program, + bpf_prog_type program_type) { + std::uint32_t linux_version{}; + + if (program_type == BPF_PROG_TYPE_KPROBE) { auto linux_version_exp = getLinuxKernelVersionCode(); if (!linux_version_exp.succeeded()) { return linux_version_exp.error(); } linux_version = linux_version_exp.takeValue(); - break; - } - - default: { - return StringError::create("Unsupported perf event type"); - } } // Load the program @@ -412,17 +435,6 @@ StringErrorOr loadProgram(const BPFProgram &program, return StringError::create(error_message); } - if (ioctl(perf_event.fd(), PERF_EVENT_IOC_SET_BPF, output.get()) < 0) { - return StringError::create( - "Failed to attach the BPF program to the perf event. Errno: " + - std::to_string(errno)); - } - - if (ioctl(perf_event.fd(), PERF_EVENT_IOC_ENABLE, 0) < 0) { - return StringError::create("Failed to enable the perf event. Errno: " + - std::to_string(errno)); - } - return output; } diff --git a/ebpf/src/feature_detect.cpp b/ebpf/src/feature_detect.cpp new file mode 100644 index 0000000..f8d42a8 --- /dev/null +++ b/ebpf/src/feature_detect.cpp @@ -0,0 +1,57 @@ +/* + Copyright (c) 2019-present, Trail of Bits, Inc. + All rights reserved. + + This source code is licensed in accordance with the terms specified in + the LICENSE file found in the root directory of this source tree. +*/ + +#include +#include +#include +#include + +namespace tob::ebpf { + +bool FeatureDetection::isHelperImplemented(bpf_func_id id) { + llvm::LLVMContext context; + auto module = createLLVMModule(context, "feature_detect_helper"); + llvm::IRBuilder<> builder{context}; + + auto function_type = llvm::FunctionType::get(builder.getInt64Ty(), false); + + auto function = builder.CreateIntToPtr( + builder.getInt64(id), llvm::PointerType::getUnqual(function_type)); + +#if LLVM_VERSION_MAJOR < 11 + auto function_callee = function; +#else + auto function_callee = llvm::FunctionCallee(function_type, function); +#endif + + builder.CreateCall(function_callee); + builder.CreateRet(builder.getInt64(0)); + + auto program_map_exp = compileModule(*module); + if (!program_map_exp.succeeded()) { + throw program_map_exp.error(); + } + + auto program_map = program_map_exp.takeValue(); + + // Get the program and load it + if (program_map.size() != 1U) { + throw StringError::create("The program was not compiled"); + } + + auto &first_program = program_map.begin()->second; + + auto program_exp = loadProgram(first_program, BPF_PROG_TYPE_UNSPEC); + if (!program_exp.succeeded()) { + return false; + } + + return true; +} + +} // namespace tob::ebpf diff --git a/utils/src/kernel.cpp b/utils/src/kernel.cpp index 2d0b1fe..5cc44ef 100644 --- a/utils/src/kernel.cpp +++ b/utils/src/kernel.cpp @@ -20,7 +20,7 @@ StringErrorOr getKernelVersion() { return StringError::create("Failed to acquire the system information"); } - std::sscanf(system_info.release, "%d.%d", &kernel_version.major, + std::sscanf(system_info.release, "%u.%u", &kernel_version.major, &kernel_version.minor); return kernel_version;