Skip to content

Commit

Permalink
Linux eBPF program to track setuid syscall
Browse files Browse the repository at this point in the history
Summary: Part of a linux  tracing system, blueprint: [osquery#5218](osquery#5218)

Differential Revision: D13669863

fbshipit-source-id: e6b400c258616edf8da725cf5c398556af660810
  • Loading branch information
akindyakov authored and facebook-github-bot committed Feb 4, 2019
1 parent 79cd575 commit be58858
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
12 changes: 12 additions & 0 deletions osquery/events/linux/probes/syscall_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ enum class Type : __s32 {
Unknown = 0,
KillEnter = 1,
KillExit = -KillEnter,
SetuidEnter = 2,
SetuidExit = -SetuidEnter,
};

static constexpr std::size_t kCommSize = 16u;
Expand All @@ -46,6 +48,16 @@ struct Event {
/* -4 */ __u32 gid;
} kill_enter;

struct SetuidEnter {
/* -40 type */
/* -36 pid */
/* -32 tgid */
/* -28 */ char comm[kCommSize];
/* -12 */ __s32 arg_uid;
/* -8 */ __u32 uid;
/* -4 */ __u32 gid;
} setuid_enter;

struct Exit {
/* -16 type */
/* -12 pid */
Expand Down
59 changes: 59 additions & 0 deletions osquery/events/linux/probes/syscalls_programs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,65 @@ Expected<ebpf::Program, ebpf::Program::Error> genLinuxKillEnterProgram(
// clang-format on
}

Expected<ebpf::Program, ebpf::Program::Error> genLinuxSetuidEnterProgram(
enum bpf_prog_type prog_type, PerfEventCpuMap const& cpu_map) {
constexpr int kSetuidEnterSize = 40;
static_assert(sizeof(syscall::Type) + sizeof(syscall::Event::pid) +
sizeof(syscall::Event::tgid) +
sizeof(syscall::Event::Body::SetuidEnter) ==
kSetuidEnterSize,
"A program below relies on certain size of output struct");
static_assert(static_cast<__s32>(syscall::Type::SetuidEnter) ==
-static_cast<__s32>(syscall::Type::SetuidExit),
"Enter and Exit codes must be convertible to each other by "
"multiplying to -1");
// 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_STX | BPF_W | BPF_MEM , BPF_REG_10, BPF_REG_1, -28, 0},
{BPF_STX | BPF_DW | BPF_MEM , BPF_REG_10, BPF_REG_1, -24, 0},
{BPF_STX | BPF_W | BPF_MEM , BPF_REG_10, BPF_REG_1, -16, 0},

// Event.type = SyscallEvent::Type::SetuidEnter
{BPF_ST | BPF_W | BPF_MEM , BPF_REG_10, 0, -kSetuidEnterSize, static_cast<__s32>(syscall::Type::SetuidEnter)},

{BPF_JMP | BPF_K | BPF_CALL , 0, 0, 0, BPF_FUNC_get_current_uid_gid},
{BPF_STX | BPF_W | BPF_MEM , BPF_REG_10, BPF_REG_0, -8, 0}, // Event.uid
{BPF_ALU64 | BPF_K | BPF_RSH , 0, 0, 0, 32},
{BPF_STX | BPF_W | BPF_MEM , BPF_REG_10, BPF_REG_0, -4, 0}, // Event.gid

{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, -36, 0}, // Event.body.pid
{BPF_ALU64 | BPF_K | BPF_RSH , 0, 0, 0, 32},
{BPF_STX | BPF_W | BPF_MEM , BPF_REG_10, BPF_REG_0, -32, 0}, // Event.body.tgid

{BPF_ALU64 | BPF_X | BPF_MOV , BPF_REG_1, BPF_REG_10, 0, 0}, // r1 = r10
{BPF_ALU64 | BPF_K | BPF_ADD , BPF_REG_1, 0, 0, -28}, // r1 += -36
{BPF_ALU64 | BPF_K | BPF_MOV , BPF_REG_2, 0, 0, syscall::kCommSize}, // r2 = SyscallEvent::kCommSize
{BPF_JMP | BPF_K | BPF_CALL , 0, 0, 0, BPF_FUNC_get_current_comm}, // call

{BPF_LDX | BPF_DW | BPF_MEM , BPF_REG_7, BPF_REG_6, 16, 0}, // see format: arg uid
{BPF_STX | BPF_W | BPF_MEM , BPF_REG_10, BPF_REG_7, -12, 0}, // Event.body.arg_uid

{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, -kSetuidEnterSize}, // r4 += -kSetuidEnterSize
{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, kSetuidEnterSize}, // r5 = kSetuidEnterSize
{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
}

Expected<ebpf::Program, ebpf::Program::Error> genLinuxExitProgram(
enum bpf_prog_type prog_type,
PerfEventCpuMap const& cpu_map,
Expand Down
3 changes: 3 additions & 0 deletions osquery/events/linux/probes/syscalls_programs.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ using PerfEventCpuMap = ebpf::Map<int, int, BPF_MAP_TYPE_PERF_EVENT_ARRAY>;
Expected<ebpf::Program, ebpf::Program::Error> genLinuxKillEnterProgram(
enum bpf_prog_type prog_type, PerfEventCpuMap const& cpu_map);

Expected<ebpf::Program, ebpf::Program::Error> genLinuxSetuidEnterProgram(
enum bpf_prog_type prog_type, PerfEventCpuMap const& cpu_map);

Expected<ebpf::Program, ebpf::Program::Error> genLinuxExitProgram(
enum bpf_prog_type prog_type,
PerfEventCpuMap const& cpu_map,
Expand Down

0 comments on commit be58858

Please sign in to comment.