From 66cf603e590f0c47de241b8ac72ac4fa38a0a33e Mon Sep 17 00:00:00 2001 From: Alexander Kindyakov Date: Thu, 31 Jan 2019 07:34:55 -0800 Subject: [PATCH] eBPF tracking program for any syscall exit event (#5403) Summary: Pull Request resolved: https://github.com/facebook/osquery/pull/5403 Part of a linux tracing system, blueprint: [#5218](https://github.com/facebook/osquery/issues/5218) Reviewed By: SAlexandru Differential Revision: D13690684 fbshipit-source-id: 039fc89929de49fcc7bd2287a98ffc68450fcada --- osquery/events/linux/probes/syscall_event.h | 16 ++++++- .../events/linux/probes/syscalls_programs.cpp | 42 +++++++++++++++++++ .../events/linux/probes/syscalls_programs.h | 5 +++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/osquery/events/linux/probes/syscall_event.h b/osquery/events/linux/probes/syscall_event.h index 959a70e80ff..e8133a07b59 100644 --- a/osquery/events/linux/probes/syscall_event.h +++ b/osquery/events/linux/probes/syscall_event.h @@ -21,15 +21,19 @@ namespace syscall { enum class Type : __s32 { Unknown = 0, KillEnter = 1, + KillExit = -KillEnter, }; static constexpr std::size_t kCommSize = 16u; struct Event { - Type type; // ebpf offset depends on the struct type in the unit + // Common part for all events whether Enter or Exit + Type type; __s32 pid; __s32 tgid; + // Body means different things for each Enter type. + // For all Exit types Body is always the same - just return value. union Body { struct KillEnter { /* -44 type */ @@ -41,7 +45,17 @@ struct Event { /* -8 */ __u32 uid; /* -4 */ __u32 gid; } kill_enter; + + struct Exit { + /* -16 type */ + /* -12 pid */ + /* -8 tgid */ + /* -4 */ __s32 ret; + } exit; } body; + + // final return value of the syscall is palced here by EnterExitJoiner + __s32 return_value; }; } // namespace syscall diff --git a/osquery/events/linux/probes/syscalls_programs.cpp b/osquery/events/linux/probes/syscalls_programs.cpp index 64f36189c20..c7ba5f6c54e 100644 --- a/osquery/events/linux/probes/syscalls_programs.cpp +++ b/osquery/events/linux/probes/syscalls_programs.cpp @@ -107,5 +107,47 @@ Expected genLinuxKillEnterProgram( // clang-format on } +Expected genLinuxExitProgram( + enum bpf_prog_type prog_type, + PerfEventCpuMap const& cpu_map, + syscall::Type type) { + constexpr int kExitSize = 16; + static_assert(sizeof(syscall::Type) + sizeof(syscall::Event::pid) + + sizeof(syscall::Event::tgid) + + sizeof(syscall::Event::Body::Exit) == + kExitSize, + "A program below relies on certain size of output struct"); + // clang-format off + return ebpf::Program::load({ + // code , dst reg , src reg , offset , immediate constant(k) + {BPF_ALU64 | BPF_X | BPF_MOV , BPF_REG_6, BPF_REG_1, 0, 0}, // r6 = r1 + {BPF_ALU64 | BPF_K | BPF_MOV , BPF_REG_1, 0, 0, 0}, // r1 = 0 + + {BPF_ST | BPF_W | BPF_MEM , BPF_REG_10, 0, -kExitSize, static_cast<__s32>(type)}, // type = syscall::Type::Exit* + + {BPF_JMP | BPF_K | BPF_CALL , 0, 0, 0, BPF_FUNC_get_current_pid_tgid}, + {BPF_STX | BPF_W | BPF_MEM , BPF_REG_10, BPF_REG_0, -12, 0}, // Event.pid + {BPF_ALU64 | BPF_K | BPF_RSH , 0, 0, 0, 32}, // r0 >>= 32 + {BPF_STX | BPF_W | BPF_MEM , BPF_REG_10, BPF_REG_0, -8, 0}, // Event.tgid + + {BPF_LDX | BPF_DW | BPF_MEM , BPF_REG_7, BPF_REG_6, 16, 0}, // see format: ret + {BPF_STX | BPF_W | BPF_MEM , BPF_REG_10, BPF_REG_7, -4, 0}, // Event.body.return_value + + {BPF_ALU64 | BPF_X | BPF_MOV , BPF_REG_4, BPF_REG_10, 0, 0}, // r4 = r10 + {BPF_ALU64 | BPF_K | BPF_ADD , BPF_REG_4, 0, 0, -kExitSize}, // r4 += -kExitSize + {BPF_ALU64 | BPF_X | BPF_MOV , BPF_REG_1, BPF_REG_6, 0, 0}, // r1 = r6 + {BPF_LD | BPF_DW | BPF_IMM , BPF_REG_2, BPF_PSEUDO_MAP_FD, 0, cpu_map.fd()}, + {BPF_LD | BPF_W | BPF_IMM , 0, 0, 0, 0}, // imm is 32, but we loading 64, so this is yet another "smart" trick + {BPF_LD | BPF_DW | BPF_IMM , BPF_REG_3, 0, 0, -1}, // r2 = -1 -> CPU + {BPF_LD | BPF_W | BPF_IMM , 0, 0, 0, 0}, // imm is 32, but we loading 64, so this is yet another "smart" trick + {BPF_ALU64 | BPF_K | BPF_MOV , BPF_REG_5, 0, 0, kExitSize}, // r5 = kExitSize + {BPF_JMP | BPF_K | BPF_CALL , 0, 0, 0, BPF_FUNC_perf_event_output}, // call + {BPF_ALU64 | BPF_K | BPF_MOV , BPF_REG_0, 0, 0, 0}, // r0 = 0 + {BPF_JMP | BPF_K | BPF_EXIT , 0, 0, 0, 0}, // exit + + }, BPF_PROG_TYPE_TRACEPOINT, kIsDebug); + // clang-format on +} + } // namespace events } // namespace osquery diff --git a/osquery/events/linux/probes/syscalls_programs.h b/osquery/events/linux/probes/syscalls_programs.h index ec1615a92f3..ba9e7cdfba0 100644 --- a/osquery/events/linux/probes/syscalls_programs.h +++ b/osquery/events/linux/probes/syscalls_programs.h @@ -24,5 +24,10 @@ using PerfEventCpuMap = ebpf::Map; Expected genLinuxKillEnterProgram( enum bpf_prog_type prog_type, PerfEventCpuMap const& cpu_map); +Expected genLinuxExitProgram( + enum bpf_prog_type prog_type, + PerfEventCpuMap const& cpu_map, + syscall::Type type); + } // namespace events } // namespace osquery