github.com/containers/podman/v5@v5.1.0-rc1/hack/podmansnoop (about) 1 #!/usr/bin/env python 2 from __future__ import print_function 3 4 # Based on the `exitsnoop` script at https://github.com/iovisor/bcc/blob/master/tools/exitsnoop.py 5 # Based on the `execsnoop` script at https://github.com/iovisor/bcc/blob/master/tools/execsnoop.py 6 7 import argparse 8 import os 9 import platform 10 import re 11 import signal 12 import sys 13 14 from bcc import BPF 15 from collections import defaultdict 16 from datetime import datetime 17 from time import strftime 18 19 bpf_src = """ 20 #include <uapi/linux/ptrace.h> 21 #include <linux/sched.h> 22 23 #define ARGSIZE 128 24 #define MAXARG 19 25 26 struct data_t { 27 u8 isArgv; 28 u64 start_time; 29 u64 exit_time; 30 u32 pid; 31 u32 ppid; 32 char comm[TASK_COMM_LEN]; 33 char argv[ARGSIZE]; 34 }; 35 36 BPF_PERF_OUTPUT(events); 37 38 TRACEPOINT_PROBE(sched, sched_process_exit) 39 { 40 struct task_struct *task = (typeof(task))bpf_get_current_task(); 41 if (task->pid != task->tgid) { return 0; } 42 43 struct data_t data = {}; 44 45 data.start_time = task->start_time, 46 data.exit_time = bpf_ktime_get_ns(), 47 data.pid = task->pid, 48 data.ppid = task->real_parent->tgid, 49 bpf_get_current_comm(&data.comm, sizeof(data.comm)); 50 51 events.perf_submit(args, &data, sizeof(data)); 52 return 0; 53 } 54 55 static int __submit_arg(struct pt_regs *ctx, void *ptr, struct data_t *data) 56 { 57 bpf_probe_read_user(data->argv, sizeof(data->argv), ptr); 58 events.perf_submit(ctx, data, sizeof(struct data_t)); 59 return 1; 60 } 61 62 static int submit_arg(struct pt_regs *ctx, void *ptr, struct data_t *data) 63 { 64 const char *argp = NULL; 65 bpf_probe_read_user(&argp, sizeof(argp), ptr); 66 if (argp) { 67 return __submit_arg(ctx, (void *)(argp), data); 68 } 69 return 0; 70 } 71 72 int syscall__execve(struct pt_regs *ctx, 73 const char __user *filename, 74 const char __user *const __user *__argv, 75 const char __user *const __user *__envp) 76 { 77 78 struct task_struct *task = (typeof(task))bpf_get_current_task(); 79 80 struct data_t data = {}; 81 data.pid = bpf_get_current_pid_tgid() >> 32; 82 data.isArgv = 1; 83 84 bpf_get_current_comm(&data.comm, sizeof(data.comm)); 85 __submit_arg(ctx, (void *)filename, &data); 86 87 // skip first arg, as we submitted filename 88 #pragma unroll 89 for (int i = 1; i < MAXARG; i++) { 90 if (submit_arg(ctx, (void *)&__argv[i], &data) == 0) 91 goto out; 92 } 93 94 // handle truncated argument list 95 char ellipsis[] = "..."; 96 __submit_arg(ctx, (void *)ellipsis, &data); 97 out: 98 99 return 0; 100 } 101 102 int do_ret_sys_execve(struct pt_regs *ctx) 103 { 104 struct task_struct *task = (typeof(task))bpf_get_current_task(); 105 106 struct data_t data = {}; 107 data.pid = bpf_get_current_pid_tgid() >> 32; 108 bpf_get_current_comm(&data.comm, sizeof(data.comm)); 109 events.perf_submit(ctx, &data, sizeof(data)); 110 return 0; 111 } 112 """ 113 114 def _print_header(): 115 print("%-16s %-7s %-7s %-7s %s" % 116 ("PCOMM", "PID", "PPID", "AGE(ms)", "ARGV")) 117 118 buffer = None 119 pidToArgv = defaultdict(list) 120 121 def _print_event(cpu, data, size): # callback 122 """Print the exit event.""" 123 global buffer 124 e = buffer["events"].event(data) 125 126 comm = e.comm.decode() 127 if comm == "3": 128 # For absolutely unknown reasons, 'crun' appears as '3'. 129 comm = "crun" 130 131 if e.isArgv: 132 pidToArgv[e.pid].append(e.argv) 133 return 134 135 if comm not in ["podman", "crun", "runc", "conmon", "netavark", "aardvark-dns"]: 136 try: 137 del(pidToArgv[e.pid]) 138 except Exception: 139 pass 140 return 141 142 age = (e.exit_time - e.start_time) / 1e6 143 argv = b' '.join(pidToArgv[e.pid]).replace(b'\n', b'\\n') 144 print("%-16s %-7d %-7d %-7.2f %s" % 145 (comm, e.pid, e.ppid, age, argv.decode()), end="") 146 print() 147 148 try: 149 del(pidToArgv[e.pid]) 150 except Exception: 151 pass 152 153 def snoop(bpf, event_handler): 154 bpf["events"].open_perf_buffer(event_handler) 155 while True: 156 bpf.perf_buffer_poll() 157 158 def main(): 159 global buffer 160 try: 161 buffer = BPF(text=bpf_src) 162 execve_fnname = buffer.get_syscall_fnname("execve") 163 buffer.attach_kprobe(event=execve_fnname, fn_name="syscall__execve") 164 _print_header() 165 snoop(buffer, _print_event) 166 except KeyboardInterrupt: 167 print() 168 sys.exit() 169 170 return 0 171 172 if __name__ == '__main__': 173 main()