Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions examples/cpp/execsnoop.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/* C++ version of execsnoop
* execsnoop traces new processes via exec() syscalls.
*
* inspired by Brendan Gregg's execsnoop
*/

#include <bcc/BPF.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <queue>
#include <mutex>

// Define the eBPF program
const std::string BPF_PROGRAM = R"(
#include<linux/ptrace.h>
#include<linux/sched.h>
#include<linux/fs.h>

enum event_type {
EVENT_ARG = 0,
EVENT_RET = 1,
};

struct data_t {
u32 pid;
u32 ppid;
char comm[TASK_COMM_LEN];
char pcomm[TASK_COMM_LEN];
char argv[128];
enum event_type type;
int8_t retval;
};

BPF_PERF_OUTPUT(events);

static int __submit_arg(struct pt_regs *ctx, void *ptr, struct data_t *data){
bpf_probe_read_user(data->argv, sizeof(data->argv), ptr);
events.perf_submit(ctx, data, sizeof(struct data_t));
return 1;
}

static int submit_args(struct pt_regs *ctx, void *ptr, struct data_t *data){
const char *argp = NULL;
bpf_probe_read_user(&argp, sizeof(argp), ptr);

if (argp) {
return __submit_arg(ctx, (void *)(argp), data);
}
return 0;
}

int syscall__execve(struct pt_regs *ctx,
const char __user *filename,
const char __user *const __user *__argv,
const char __user *const __user *__envp) {

struct data_t data = {};
struct task_struct *task;

data.pid = bpf_get_current_pid_tgid() >> 32;
task = (struct task_struct *)bpf_get_current_task();
data.ppid = task->real_parent->tgid;
bpf_probe_read_kernel_str(&data.pcomm, sizeof(data.pcomm), task->real_parent->comm);

bpf_get_current_comm(&data.comm, sizeof(data.comm));
data.type = EVENT_ARG;
__submit_arg(ctx, (void *)filename, &data);

for (int i = 1; i < 10; i++) {
if (submit_args(ctx, (void *)&__argv[i], &data) == 0) {
goto out;
}
}

char ellipsis[] = "...";
__submit_arg(ctx, (void *)ellipsis, &data);

out:
return 0;
}

int do_ret_execve(struct pt_regs *ctx) {
struct data_t data = {};
struct task_struct *task;

data.pid = bpf_get_current_pid_tgid();
task = (struct task_struct *)bpf_get_current_task();
data.ppid = task->real_parent->tgid;
bpf_probe_read_kernel_str(&data.pcomm, sizeof(data.pcomm), task->real_parent->comm);
bpf_get_current_comm(&data.comm, sizeof(data.comm));

data.type = EVENT_RET;
data.retval = PT_REGS_RC(ctx);

events.perf_submit(ctx, &data, sizeof(data));

return 0;
}

)";

enum event_type {
EVENT_ARG = 0,
EVENT_RET = 1,
};

struct data_t {
uint32_t pid ;
uint32_t ppid;
char comm[16];
char pcomm[16];
char args[128];
enum event_type type;
int8_t retval;
};

std::queue<std::string> args;

int get_args(struct data_t* event) {
while (!args.empty()) {
std::cout << args.front() << " ";
args.pop();
}
std::cout << std::endl;
return 0;
}

void handle_event(void *ctx, void *data, int data_size) {
auto *event = static_cast<data_t *>(data);

if (event->type == EVENT_ARG) {
args.push(event->args);
} else if (event->type == EVENT_RET) {
std::cout << "PID: " << event->pid
<< "\tPPID: " << event->ppid
<< "\tCOMM: " << event->comm
<< "\tARGS: ";
get_args(event);
}
}

int main() {
ebpf::BPF bpf;

// Initialize BPF program
auto init_res = bpf.init(BPF_PROGRAM);
if (!init_res.ok()) {
std::cerr << init_res.msg() << std::endl;
return 1;
}

// Attach to tracepoint for execve syscall
std::string execve_fnname = bpf.get_syscall_fnname("execve");
auto attach_res = bpf.attach_kprobe(execve_fnname, "syscall__execve");
if (!attach_res.ok()) {
std::cerr << attach_res.msg() << std::endl;
return 1;
}

auto attach_ret = bpf.attach_kprobe(execve_fnname, "do_ret_execve", 0, BPF_PROBE_RETURN, 0);
if (!attach_ret.ok()) {
std::cerr << attach_ret.msg() << std::endl;
return 1;
}

// Open perf buffer to receive events
auto perf_buffer = bpf.open_perf_buffer("events", handle_event);
if (!perf_buffer.ok()) {
std::cerr << perf_buffer.msg() << std::endl;
return 1;
}

std::cout << "Tracing execve syscalls... Press Ctrl+C to stop." << std::endl;

// Poll events
while (true) {
bpf.poll_perf_buffer("events", 100);
}

return 0;
}