1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# filegone Trace why file gone (deleted or renamed). 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. Embedded C. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# USAGE: filegone [-h] [-p PID] 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 10*387f9dfdSAndroid Build Coastguard Worker# 11*387f9dfdSAndroid Build Coastguard Worker# 08-Nov-2022 Curu. modified from filelife 12*387f9dfdSAndroid Build Coastguard Worker 13*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 14*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 15*387f9dfdSAndroid Build Coastguard Workerimport argparse 16*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime 17*387f9dfdSAndroid Build Coastguard Worker 18*387f9dfdSAndroid Build Coastguard Worker# arguments 19*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 20*387f9dfdSAndroid Build Coastguard Worker ./filegone # trace all file gone events 21*387f9dfdSAndroid Build Coastguard Worker ./filegone -p 181 # only trace PID 181 22*387f9dfdSAndroid Build Coastguard Worker""" 23*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 24*387f9dfdSAndroid Build Coastguard Worker description="Trace why file gone (deleted or renamed)", 25*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 26*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 27*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", 28*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 29*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 30*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 31*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 32*387f9dfdSAndroid Build Coastguard Workerdebug = 0 33*387f9dfdSAndroid Build Coastguard Worker 34*387f9dfdSAndroid Build Coastguard Worker# define BPF program 35*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 36*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 37*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h> 38*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 39*387f9dfdSAndroid Build Coastguard Worker 40*387f9dfdSAndroid Build Coastguard Workerstruct data_t { 41*387f9dfdSAndroid Build Coastguard Worker u32 pid; 42*387f9dfdSAndroid Build Coastguard Worker u8 action; 43*387f9dfdSAndroid Build Coastguard Worker char comm[TASK_COMM_LEN]; 44*387f9dfdSAndroid Build Coastguard Worker char fname[DNAME_INLINE_LEN]; 45*387f9dfdSAndroid Build Coastguard Worker char fname2[DNAME_INLINE_LEN]; 46*387f9dfdSAndroid Build Coastguard Worker}; 47*387f9dfdSAndroid Build Coastguard Worker 48*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events); 49*387f9dfdSAndroid Build Coastguard Worker 50*387f9dfdSAndroid Build Coastguard Worker// trace file deletion and output details 51*387f9dfdSAndroid Build Coastguard Worker#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0) 52*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry) 53*387f9dfdSAndroid Build Coastguard Worker#else 54*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct user_namespace *ns, struct inode *dir, struct dentry *dentry) 55*387f9dfdSAndroid Build Coastguard Worker#endif 56*387f9dfdSAndroid Build Coastguard Worker{ 57*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 58*387f9dfdSAndroid Build Coastguard Worker 59*387f9dfdSAndroid Build Coastguard Worker FILTER 60*387f9dfdSAndroid Build Coastguard Worker 61*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 62*387f9dfdSAndroid Build Coastguard Worker struct qstr d_name = dentry->d_name; 63*387f9dfdSAndroid Build Coastguard Worker if (d_name.len == 0) 64*387f9dfdSAndroid Build Coastguard Worker return 0; 65*387f9dfdSAndroid Build Coastguard Worker 66*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data.comm, sizeof(data.comm)); 67*387f9dfdSAndroid Build Coastguard Worker data.pid = pid; 68*387f9dfdSAndroid Build Coastguard Worker data.action = 'D'; 69*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read(&data.fname, sizeof(data.fname), d_name.name); 70*387f9dfdSAndroid Build Coastguard Worker 71*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 72*387f9dfdSAndroid Build Coastguard Worker 73*387f9dfdSAndroid Build Coastguard Worker return 0; 74*387f9dfdSAndroid Build Coastguard Worker} 75*387f9dfdSAndroid Build Coastguard Worker 76*387f9dfdSAndroid Build Coastguard Worker// trace file rename 77*387f9dfdSAndroid Build Coastguard Worker#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0) 78*387f9dfdSAndroid Build Coastguard Workerint trace_rename(struct pt_regs *ctx, struct inode *old_dir, struct dentry *old_dentry, 79*387f9dfdSAndroid Build Coastguard Workerstruct inode *new_dir, struct dentry *new_dentry) 80*387f9dfdSAndroid Build Coastguard Worker{ 81*387f9dfdSAndroid Build Coastguard Worker#else 82*387f9dfdSAndroid Build Coastguard Workerint trace_rename(struct pt_regs *ctx, struct renamedata *rd) 83*387f9dfdSAndroid Build Coastguard Worker{ 84*387f9dfdSAndroid Build Coastguard Worker struct dentry *old_dentry = rd->old_dentry; 85*387f9dfdSAndroid Build Coastguard Worker struct dentry *new_dentry = rd->new_dentry; 86*387f9dfdSAndroid Build Coastguard Worker#endif 87*387f9dfdSAndroid Build Coastguard Worker 88*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 89*387f9dfdSAndroid Build Coastguard Worker 90*387f9dfdSAndroid Build Coastguard Worker FILTER 91*387f9dfdSAndroid Build Coastguard Worker 92*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 93*387f9dfdSAndroid Build Coastguard Worker struct qstr s_name = old_dentry->d_name; 94*387f9dfdSAndroid Build Coastguard Worker struct qstr d_name = new_dentry->d_name; 95*387f9dfdSAndroid Build Coastguard Worker if (s_name.len == 0 || d_name.len == 0) 96*387f9dfdSAndroid Build Coastguard Worker return 0; 97*387f9dfdSAndroid Build Coastguard Worker 98*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data.comm, sizeof(data.comm)); 99*387f9dfdSAndroid Build Coastguard Worker data.pid = pid; 100*387f9dfdSAndroid Build Coastguard Worker data.action = 'R'; 101*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read(&data.fname, sizeof(data.fname), s_name.name); 102*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read(&data.fname2, sizeof(data.fname), d_name.name); 103*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 104*387f9dfdSAndroid Build Coastguard Worker 105*387f9dfdSAndroid Build Coastguard Worker return 0; 106*387f9dfdSAndroid Build Coastguard Worker} 107*387f9dfdSAndroid Build Coastguard Worker""" 108*387f9dfdSAndroid Build Coastguard Worker 109*387f9dfdSAndroid Build Coastguard Worker 110*387f9dfdSAndroid Build Coastguard Workerdef action2str(action): 111*387f9dfdSAndroid Build Coastguard Worker if chr(action) == 'D': 112*387f9dfdSAndroid Build Coastguard Worker action_str = "DELETE" 113*387f9dfdSAndroid Build Coastguard Worker else: 114*387f9dfdSAndroid Build Coastguard Worker action_str = "RENAME" 115*387f9dfdSAndroid Build Coastguard Worker return action_str 116*387f9dfdSAndroid Build Coastguard Worker 117*387f9dfdSAndroid Build Coastguard Workerif args.pid: 118*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER', 119*387f9dfdSAndroid Build Coastguard Worker 'if (pid != %s) { return 0; }' % args.pid) 120*387f9dfdSAndroid Build Coastguard Workerelse: 121*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER', '') 122*387f9dfdSAndroid Build Coastguard Worker 123*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 124*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 125*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 126*387f9dfdSAndroid Build Coastguard Worker exit() 127*387f9dfdSAndroid Build Coastguard Worker 128*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 129*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 130*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_unlink", fn_name="trace_unlink") 131*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_rmdir", fn_name="trace_unlink") 132*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_rename", fn_name="trace_rename") 133*387f9dfdSAndroid Build Coastguard Worker 134*387f9dfdSAndroid Build Coastguard Worker# header 135*387f9dfdSAndroid Build Coastguard Workerprint("%-8s %-7s %-16s %6s %s" % ("TIME", "PID", "COMM", "ACTION", "FILE")) 136*387f9dfdSAndroid Build Coastguard Worker 137*387f9dfdSAndroid Build Coastguard Worker# process event 138*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 139*387f9dfdSAndroid Build Coastguard Worker event = b["events"].event(data) 140*387f9dfdSAndroid Build Coastguard Worker action_str = action2str(event.action) 141*387f9dfdSAndroid Build Coastguard Worker file_str = event.fname.decode('utf-8', 'replace') 142*387f9dfdSAndroid Build Coastguard Worker if action_str == "RENAME": 143*387f9dfdSAndroid Build Coastguard Worker file_str = "%s > %s" % (file_str, event.fname2.decode('utf-8', 'replace')) 144*387f9dfdSAndroid Build Coastguard Worker print("%-8s %-7d %-16s %6s %s" % (strftime("%H:%M:%S"), event.pid, 145*387f9dfdSAndroid Build Coastguard Worker event.comm.decode('utf-8', 'replace'), action_str, file_str)) 146*387f9dfdSAndroid Build Coastguard Worker 147*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event) 148*387f9dfdSAndroid Build Coastguard Workerwhile 1: 149*387f9dfdSAndroid Build Coastguard Worker try: 150*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 151*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 152*387f9dfdSAndroid Build Coastguard Worker exit() 153