diff --git a/.gitignore b/.gitignore index 378eac2..67f0073 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ build +.cache + diff --git a/src/faultinjector.cpp b/src/faultinjector.cpp index 7f72746..55f7ba7 100644 --- a/src/faultinjector.cpp +++ b/src/faultinjector.cpp @@ -9,6 +9,8 @@ #include "faultinjector.h" #include "utils.h" +#include + #include #include @@ -17,6 +19,32 @@ #include namespace tob::ebpfault { + +namespace { + +// +// Register list. Make sure that the order is the same as the +// struct pt_regs definition! +// + +const std::vector 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_) {} @@ -56,6 +84,44 @@ std::uint64_t FaultInjector::eventIdentifier() const { return static_cast(d->kprobe_event->fd()); } +std::vector +FaultInjector::parseEventData(utils::BufferReader &buffer_reader, + ebpf::PerfEventArray::BufferList &&buffer_list) { + + std::vector 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 ®ister_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) @@ -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 @@ -113,22 +180,25 @@ SuccessOrStringError FaultInjector::generateBPFProgram() { d->module = ebpf::createLLVMModule(d->context, d->config.name + "_FaultInjector"); - // Generate the pt_regs structure - std::vector 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(25U, llvm::Type::getInt64Ty(d->context)); + // injected error + pt_regs) + std::vector 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( @@ -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); @@ -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(); @@ -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(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); } diff --git a/src/faultinjector.h b/src/faultinjector.h index c501484..8e07f0a 100644 --- a/src/faultinjector.h +++ b/src/faultinjector.h @@ -11,13 +11,15 @@ #include "configuration.h" #include -#include +#include #include #include #include +#include + #include namespace tob::ebpfault { @@ -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 register_map; }; using Ref = std::unique_ptr; @@ -71,6 +53,10 @@ class FaultInjector final { FaultInjector(const FaultInjector &) = delete; FaultInjector &operator=(const FaultInjector &) = delete; + static std::vector + parseEventData(utils::BufferReader &buffer_reader, + ebpf::PerfEventArray::BufferList &&buffer_list); + private: struct PrivateData; std::unique_ptr d; diff --git a/src/main.cpp b/src/main.cpp index ce085b6..79d6e76 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,60 +33,13 @@ std::unordered_map event_name_map; -std::optional -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); @@ -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 ®ister_map_p : event_data.register_map) { + const auto ®ister_name = register_map_p.first; + const auto ®ister_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; + } } } @@ -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 exec_argv; for (auto ¶m : exec_command_line) {