Skip to content

Commit

Permalink
FaultInjector: Fix register dump on fault injection (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
alessandrogario authored Jan 6, 2023
1 parent ce493f7 commit 1907278
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 130 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
build
.cache

125 changes: 99 additions & 26 deletions src/faultinjector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "faultinjector.h"
#include "utils.h"

#include <iostream>

#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Module.h>

Expand All @@ -17,6 +19,32 @@
#include <tob/ebpf/llvm_utils.h>

namespace tob::ebpfault {

namespace {

//
// Register list. Make sure that the order is the same as the
// struct pt_regs definition!
//

const std::vector<std::string> kRegisterList {
#if __x86_64__
"r15", "r14", "r13", "r12", "rbp", "rbx", "r11", "r10", "r9", "r8", "rax",
"rcx", "rdx", "rsi", "rdi", "orig_rax", "rip", "cs", "eflags", "rsp", "ss"

#elif __arm__ || __aarch64__
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
"r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
"r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "sp", "pc",
"pstate"

#else
#error Unsupported architecture
#endif
};

} // namespace

struct FaultInjector::PrivateData final {
PrivateData(ebpf::PerfEventArray &perf_event_array_)
: perf_event_array(perf_event_array_) {}
Expand Down Expand Up @@ -56,6 +84,44 @@ std::uint64_t FaultInjector::eventIdentifier() const {
return static_cast<std::uint64_t>(d->kprobe_event->fd());
}

std::vector<FaultInjector::EventData>
FaultInjector::parseEventData(utils::BufferReader &buffer_reader,
ebpf::PerfEventArray::BufferList &&buffer_list) {

std::vector<FaultInjector::EventData> event_data_list;

for (const auto &buffer : buffer_list) {
buffer_reader.reset(buffer);
buffer_reader.skipBytes(tob::ebpf::kPerfEventHeaderSize +
sizeof(std::uint32_t));

EventData event_data{};

try {
event_data.timestamp = buffer_reader.u64();
event_data.event_id = buffer_reader.u64();
event_data.process_id = buffer_reader.u32();
event_data.thread_id = buffer_reader.u32();
event_data.injected_error = buffer_reader.u64();

for (const auto &register_name : kRegisterList) {
auto register_value = buffer_reader.u64();
event_data.register_map.insert({register_name, register_value});
}

event_data_list.push_back(std::move(event_data));

} catch (...) {
std::cerr
<< "Failed to read the current event. Skipping to the next one...\n";
}

event_data = {};
}

return event_data_list;
}

FaultInjector::FaultInjector(ebpf::PerfEventArray &perf_event_array,
const Configuration::SyscallFault &config,
const ProcessIDFilter &filter)
Expand All @@ -76,13 +142,14 @@ FaultInjector::FaultInjector(ebpf::PerfEventArray &perf_event_array,
}

std::string arch;
#if __x86_64__
arch = "x64";
#elif __arm__ || __aarch64__
arch = "arm64";
#else
throw StringError::create("The current architecture is not valid. Supported: arm or x86_64.");
#endif
#if __x86_64__
arch = "x64";
#elif __arm__ || __aarch64__
arch = "arm64";
#else
throw StringError::create(
"The current architecture is not valid. Supported: arm or x86_64.");
#endif

// Create the event first, so we know whether the given system call exists or
// not
Expand Down Expand Up @@ -113,22 +180,25 @@ SuccessOrStringError FaultInjector::generateBPFProgram() {
d->module =
ebpf::createLLVMModule(d->context, d->config.name + "_FaultInjector");

// Generate the pt_regs structure
std::vector<llvm::Type *> type_list(21U, llvm::Type::getInt64Ty(d->context));
auto pt_regs_struct = llvm::StructType::create(type_list, "pt_regs", false);
// Get the pt_regs structure for our processor
auto pt_regs_struct_exp =
ebpf::getPtRegsStructure(*d->module.get(), "pt_regs");

if (pt_regs_struct == nullptr) {
return StringError::create("Failed to create the pt_regs structure type");
if (!pt_regs_struct_exp.succeeded()) {
return pt_regs_struct_exp.error();
}

auto pt_regs_struct = pt_regs_struct_exp.takeValue();

// Generate the event data structure (timestamp + event_id + (pid/tgid) +
// injected error
// + pt_regs)
type_list =
std::vector<llvm::Type *>(25U, llvm::Type::getInt64Ty(d->context));
// injected error + pt_regs)
std::vector<llvm::Type *> event_data_type_list(
4U, llvm::Type::getInt64Ty(d->context));

event_data_type_list.push_back(pt_regs_struct);

auto event_data_struct =
llvm::StructType::create(type_list, "EventData", true);
llvm::StructType::create(event_data_type_list, "EventData", true);

if (event_data_struct == nullptr) {
return StringError::create(
Expand Down Expand Up @@ -161,8 +231,7 @@ SuccessOrStringError FaultInjector::generateBPFProgram() {
auto entry_bb = llvm::BasicBlock::Create(d->context, "entry", function);

// Allocate space for the event data
llvm::IRBuilder<> builder(d->context);
builder.SetInsertPoint(entry_bb);
llvm::IRBuilder<> builder(entry_bb);

auto event_data = builder.CreateAlloca(event_data_struct);

Expand Down Expand Up @@ -290,11 +359,8 @@ SuccessOrStringError FaultInjector::generateFaultSelector(

builder.SetInsertPoint(fail_syscall_bb);

//
// Populate the event data structure (timestamp + event_id + (pid/tgid) +
// injected error
// + pt_regs)
//
// injected error + pt_regs)

// Timestamp
auto timestamp = bpf_syscall_interface.ktimeGetNs();
Expand Down Expand Up @@ -326,15 +392,22 @@ SuccessOrStringError FaultInjector::generateFaultSelector(
builder.CreateStore(builder.getInt64(fault.exit_code),
event_data_field_ptr);

// Context structure
for (std::uint32_t i = 0U; i < 21U; ++i) {
// pt_regs structure
auto &module = *fail_syscall_bb->getModule();

auto pt_regs_type = module.getTypeByName("pt_regs");
auto pt_regs_member_count =
static_cast<std::uint32_t>(pt_regs_type->getNumElements());

for (std::uint32_t i = 0U; i < pt_regs_member_count; ++i) {
auto reg_value_ptr = builder.CreateGEP(
pt_regs, {builder.getInt32(0), builder.getInt32(i)});

auto reg_value = builder.CreateLoad(reg_value_ptr);

auto reg_dest_ptr = builder.CreateGEP(
event_data, {builder.getInt32(0), builder.getInt32(4 + i)});
event_data,
{builder.getInt32(0), builder.getInt32(4U), builder.getInt32(i)});

builder.CreateStore(reg_value, reg_dest_ptr);
}
Expand Down
30 changes: 8 additions & 22 deletions src/faultinjector.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
#include "configuration.h"

#include <memory>
#include <unordered_set>
#include <unordered_map>

#include <llvm/IR/IRBuilder.h>

#include <tob/ebpf/bpfsyscallinterface.h>
#include <tob/ebpf/perfeventarray.h>

#include <tob/utils/bufferreader.h>

#include <tob/error/stringerror.h>

namespace tob::ebpfault {
Expand All @@ -36,27 +38,7 @@ class FaultInjector final {
std::uint32_t process_id;
std::uint32_t thread_id;
std::uint64_t injected_error;
std::uint64_t r15;
std::uint64_t r14;
std::uint64_t r13;
std::uint64_t r12;
std::uint64_t rbp;
std::uint64_t rbx;
std::uint64_t r11;
std::uint64_t r10;
std::uint64_t r9;
std::uint64_t r8;
std::uint64_t rax;
std::uint64_t rcx;
std::uint64_t rdx;
std::uint64_t rsi;
std::uint64_t rdi;
std::uint64_t orig_rax;
std::uint64_t rip;
std::uint64_t cs;
std::uint64_t eflags;
std::uint64_t rsp;
std::uint64_t ss;
std::unordered_map<std::string, std::uint64_t> register_map;
};

using Ref = std::unique_ptr<FaultInjector>;
Expand All @@ -71,6 +53,10 @@ class FaultInjector final {
FaultInjector(const FaultInjector &) = delete;
FaultInjector &operator=(const FaultInjector &) = delete;

static std::vector<EventData>
parseEventData(utils::BufferReader &buffer_reader,
ebpf::PerfEventArray::BufferList &&buffer_list);

private:
struct PrivateData;
std::unique_ptr<PrivateData> d;
Expand Down
97 changes: 15 additions & 82 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,60 +33,13 @@

std::unordered_map<std::uint64_t, std::string> event_name_map;

std::optional<tob::ebpfault::FaultInjector::EventData>
getEventData(tob::utils::BufferReader &buffer_reader) {
tob::ebpfault::FaultInjector::EventData event_data;

try {
event_data.timestamp = buffer_reader.u64();
event_data.event_id = buffer_reader.u64();
event_data.process_id = buffer_reader.u32();
event_data.thread_id = buffer_reader.u32();
event_data.injected_error = buffer_reader.u64();
event_data.r15 = buffer_reader.u64();
event_data.r14 = buffer_reader.u64();
event_data.r13 = buffer_reader.u64();
event_data.r12 = buffer_reader.u64();
event_data.rbp = buffer_reader.u64();
event_data.rbx = buffer_reader.u64();
event_data.r11 = buffer_reader.u64();
event_data.r10 = buffer_reader.u64();
event_data.r9 = buffer_reader.u64();
event_data.r8 = buffer_reader.u64();
event_data.rax = buffer_reader.u64();
event_data.rcx = buffer_reader.u64();
event_data.rdx = buffer_reader.u64();
event_data.rsi = buffer_reader.u64();
event_data.rdi = buffer_reader.u64();
event_data.orig_rax = buffer_reader.u64();
event_data.rip = buffer_reader.u64();
event_data.cs = buffer_reader.u64();
event_data.eflags = buffer_reader.u64();
event_data.rsp = buffer_reader.u64();
event_data.ss = buffer_reader.u64();

return event_data;

} catch (...) {
return std::nullopt;
}
}

void printEventData(tob::utils::BufferReader &buffer_reader,
tob::ebpf::PerfEventArray::BufferList buffer_list) {

for (const auto &buffer : buffer_list) {
buffer_reader.reset(buffer);
buffer_reader.skipBytes(tob::ebpf::kPerfEventHeaderSize +
sizeof(std::uint32_t));
auto event_data_list = tob::ebpfault::FaultInjector::parseEventData(
buffer_reader, std::move(buffer_list));

auto opt_event_data = getEventData(buffer_reader);
if (!opt_event_data.has_value()) {
std::cerr << "Read error. Skipping event\n";
continue;
}

const auto &event_data = opt_event_data.value();
for (const auto &event_data : event_data_list) {

std::string event_name;
auto event_name_it = event_name_map.find(event_data.event_id);
Expand All @@ -103,40 +56,21 @@ void printEventData(tob::utils::BufferReader &buffer_reader,
<< tob::ebpfault::describeFaultValue(event_data.injected_error)
<< "\n";

EBPFAULT_DUMP_REGISTER(r15);
EBPFAULT_DUMP_REGISTER(r14);
EBPFAULT_DUMP_REGISTER(r13);
std::cout << "\n";
std::size_t index{1};
for (const auto &register_map_p : event_data.register_map) {
const auto &register_name = register_map_p.first;
const auto &register_value = register_map_p.second;

EBPFAULT_DUMP_REGISTER(r12);
EBPFAULT_DUMP_REGISTER(rbp);
EBPFAULT_DUMP_REGISTER(rbx);
std::cout << "\n";
std::cout << std::setfill(' ') << std::setw(10) << register_name << " "
<< std::hex << std::setfill('0') << std::setw(16)
<< register_value << " ";

EBPFAULT_DUMP_REGISTER(r11);
EBPFAULT_DUMP_REGISTER(r10);
EBPFAULT_DUMP_REGISTER(r9);
std::cout << "\n";

EBPFAULT_DUMP_REGISTER(r8);
EBPFAULT_DUMP_REGISTER(rax);
EBPFAULT_DUMP_REGISTER(rcx);
std::cout << "\n";

EBPFAULT_DUMP_REGISTER(rdx);
EBPFAULT_DUMP_REGISTER(rsi);
EBPFAULT_DUMP_REGISTER(rdi);
std::cout << "\n";

EBPFAULT_DUMP_REGISTER(orig_rax);
EBPFAULT_DUMP_REGISTER(rip);
EBPFAULT_DUMP_REGISTER(cs);
std::cout << "\n";
if ((index % 3) == 0) {
std::cout << "\n";
}

EBPFAULT_DUMP_REGISTER(eflags);
EBPFAULT_DUMP_REGISTER(rsp);
EBPFAULT_DUMP_REGISTER(ss);
std::cout << "\n\n";
++index;
}
}
}

Expand Down Expand Up @@ -205,7 +139,6 @@ int main(int argc, char *argv[], char *envp[]) {
command_line_params.opt_exec_command_line.value();

auto path = exec_command_line.at(0);
// exec_command_line.erase(exec_command_line.begin());

std::vector<char *> exec_argv;
for (auto &param : exec_command_line) {
Expand Down

0 comments on commit 1907278

Please sign in to comment.