From be58858e884649f1f170b09e52f70dbc6008fdf8 Mon Sep 17 00:00:00 2001 From: Alexander Kindyakov Date: Mon, 4 Feb 2019 06:29:05 -0800 Subject: [PATCH] Linux eBPF program to track setuid syscall Summary: Part of a linux tracing system, blueprint: [#5218](https://github.com/facebook/osquery/issues/5218) Differential Revision: D13669863 fbshipit-source-id: e6b400c258616edf8da725cf5c398556af660810 --- osquery/events/linux/probes/syscall_event.h | 12 ++++ .../events/linux/probes/syscalls_programs.cpp | 59 +++++++++++++++++++ .../events/linux/probes/syscalls_programs.h | 3 + 3 files changed, 74 insertions(+) diff --git a/osquery/events/linux/probes/syscall_event.h b/osquery/events/linux/probes/syscall_event.h index e8133a07b59..1d646d06d29 100644 --- a/osquery/events/linux/probes/syscall_event.h +++ b/osquery/events/linux/probes/syscall_event.h @@ -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; @@ -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 */ diff --git a/osquery/events/linux/probes/syscalls_programs.cpp b/osquery/events/linux/probes/syscalls_programs.cpp index c7ba5f6c54e..ed2a1f293b5 100644 --- a/osquery/events/linux/probes/syscalls_programs.cpp +++ b/osquery/events/linux/probes/syscalls_programs.cpp @@ -107,6 +107,65 @@ Expected genLinuxKillEnterProgram( // clang-format on } +Expected 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 genLinuxExitProgram( enum bpf_prog_type prog_type, PerfEventCpuMap const& cpu_map, diff --git a/osquery/events/linux/probes/syscalls_programs.h b/osquery/events/linux/probes/syscalls_programs.h index ba9e7cdfba0..947ffd3f940 100644 --- a/osquery/events/linux/probes/syscalls_programs.h +++ b/osquery/events/linux/probes/syscalls_programs.h @@ -24,6 +24,9 @@ using PerfEventCpuMap = ebpf::Map; Expected genLinuxKillEnterProgram( enum bpf_prog_type prog_type, PerfEventCpuMap const& cpu_map); +Expected genLinuxSetuidEnterProgram( + enum bpf_prog_type prog_type, PerfEventCpuMap const& cpu_map); + Expected genLinuxExitProgram( enum bpf_prog_type prog_type, PerfEventCpuMap const& cpu_map,