diff --git a/examples/cpp/execsnoop.cc b/examples/cpp/execsnoop.cc new file mode 100644 index 000000000000..0d47526714f0 --- /dev/null +++ b/examples/cpp/execsnoop.cc @@ -0,0 +1,185 @@ +/* C++ version of execsnoop + * execsnoop traces new processes via exec() syscalls. + * + * inspired by Brendan Gregg's execsnoop + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Define the eBPF program +const std::string BPF_PROGRAM = R"( +#include +#include +#include + +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 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); + + 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; +}