Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

WIP: Feature Detection: Check if Helper Function Exists #30

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ebpf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions ebpf/include/tob/ebpf/ebpf_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ createPerfEventOutputForCPU(std::size_t processor_index,

StringErrorOr<utils::UniqueFd> loadProgram(const BPFProgram &program,
IPerfEvent &perf_event);
StringErrorOr<utils::UniqueFd>
loadProgram(const BPFProgram &program,
bpf_prog_type program_type = BPF_PROG_TYPE_UNSPEC);

StringErrorOr<std::uint32_t> getLinuxKernelVersionCode();
} // namespace tob::ebpf
20 changes: 20 additions & 0 deletions ebpf/include/tob/ebpf/feature_detect.h
Original file line number Diff line number Diff line change
@@ -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 <linux/bpf.h>

namespace tob::ebpf {

class FeatureDetection {
public:
static bool isHelperImplemented(bpf_func_id id);
};

} // namespace tob::ebpf
52 changes: 32 additions & 20 deletions ebpf/src/ebpf_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,7 @@ createPerfEventOutputForCPU(std::size_t processor_index,

StringErrorOr<utils::UniqueFd> 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: {
Expand All @@ -347,19 +345,44 @@ StringErrorOr<utils::UniqueFd> 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<utils::UniqueFd> 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
Expand Down Expand Up @@ -412,17 +435,6 @@ StringErrorOr<utils::UniqueFd> 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;
}

Expand Down
57 changes: 57 additions & 0 deletions ebpf/src/feature_detect.cpp
Original file line number Diff line number Diff line change
@@ -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 <llvm/IR/IRBuilder.h>
#include <tob/ebpf/ebpf_utils.h>
#include <tob/ebpf/feature_detect.h>
#include <tob/ebpf/llvm_utils.h>

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
2 changes: 1 addition & 1 deletion utils/src/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ StringErrorOr<KernelVersion> 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;
Expand Down