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# 19-Nov-2022 Rong Tao Check btf struct field instead of KERNEL_VERSION macro. 13*387f9dfdSAndroid Build Coastguard Worker 14*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 15*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 16*387f9dfdSAndroid Build Coastguard Workerimport argparse 17*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime 18*387f9dfdSAndroid Build Coastguard Worker 19*387f9dfdSAndroid Build Coastguard Worker# arguments 20*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 21*387f9dfdSAndroid Build Coastguard Worker ./filegone # trace all file gone events 22*387f9dfdSAndroid Build Coastguard Worker ./filegone -p 181 # only trace PID 181 23*387f9dfdSAndroid Build Coastguard Worker""" 24*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 25*387f9dfdSAndroid Build Coastguard Worker description="Trace why file gone (deleted or renamed)", 26*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 27*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 28*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", 29*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 30*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 31*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 32*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 33*387f9dfdSAndroid Build Coastguard Workerdebug = 0 34*387f9dfdSAndroid Build Coastguard Worker 35*387f9dfdSAndroid Build Coastguard Worker# define BPF program 36*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 37*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 38*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h> 39*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 40*387f9dfdSAndroid Build Coastguard Worker 41*387f9dfdSAndroid Build Coastguard Workerstruct data_t { 42*387f9dfdSAndroid Build Coastguard Worker u32 pid; 43*387f9dfdSAndroid Build Coastguard Worker u8 action; 44*387f9dfdSAndroid Build Coastguard Worker char comm[TASK_COMM_LEN]; 45*387f9dfdSAndroid Build Coastguard Worker char fname[DNAME_INLINE_LEN]; 46*387f9dfdSAndroid Build Coastguard Worker char fname2[DNAME_INLINE_LEN]; 47*387f9dfdSAndroid Build Coastguard Worker}; 48*387f9dfdSAndroid Build Coastguard Worker 49*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events); 50*387f9dfdSAndroid Build Coastguard Worker 51*387f9dfdSAndroid Build Coastguard Worker// trace file deletion and output details 52*387f9dfdSAndroid Build Coastguard WorkerTRACE_VFS_UNLINK_FUNC 53*387f9dfdSAndroid Build Coastguard Worker{ 54*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 55*387f9dfdSAndroid Build Coastguard Worker 56*387f9dfdSAndroid Build Coastguard Worker FILTER 57*387f9dfdSAndroid Build Coastguard Worker 58*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 59*387f9dfdSAndroid Build Coastguard Worker struct qstr d_name = dentry->d_name; 60*387f9dfdSAndroid Build Coastguard Worker if (d_name.len == 0) 61*387f9dfdSAndroid Build Coastguard Worker return 0; 62*387f9dfdSAndroid Build Coastguard Worker 63*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data.comm, sizeof(data.comm)); 64*387f9dfdSAndroid Build Coastguard Worker data.pid = pid; 65*387f9dfdSAndroid Build Coastguard Worker data.action = 'D'; 66*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read(&data.fname, sizeof(data.fname), d_name.name); 67*387f9dfdSAndroid Build Coastguard Worker 68*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 69*387f9dfdSAndroid Build Coastguard Worker 70*387f9dfdSAndroid Build Coastguard Worker return 0; 71*387f9dfdSAndroid Build Coastguard Worker} 72*387f9dfdSAndroid Build Coastguard Worker 73*387f9dfdSAndroid Build Coastguard Worker// trace file rename 74*387f9dfdSAndroid Build Coastguard WorkerTRACE_VFS_RENAME_FUNC 75*387f9dfdSAndroid Build Coastguard Worker 76*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 77*387f9dfdSAndroid Build Coastguard Worker 78*387f9dfdSAndroid Build Coastguard Worker FILTER 79*387f9dfdSAndroid Build Coastguard Worker 80*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 81*387f9dfdSAndroid Build Coastguard Worker struct qstr s_name = old_dentry->d_name; 82*387f9dfdSAndroid Build Coastguard Worker struct qstr d_name = new_dentry->d_name; 83*387f9dfdSAndroid Build Coastguard Worker if (s_name.len == 0 || d_name.len == 0) 84*387f9dfdSAndroid Build Coastguard Worker return 0; 85*387f9dfdSAndroid Build Coastguard Worker 86*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data.comm, sizeof(data.comm)); 87*387f9dfdSAndroid Build Coastguard Worker data.pid = pid; 88*387f9dfdSAndroid Build Coastguard Worker data.action = 'R'; 89*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read(&data.fname, sizeof(data.fname), s_name.name); 90*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read(&data.fname2, sizeof(data.fname), d_name.name); 91*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 92*387f9dfdSAndroid Build Coastguard Worker 93*387f9dfdSAndroid Build Coastguard Worker return 0; 94*387f9dfdSAndroid Build Coastguard Worker} 95*387f9dfdSAndroid Build Coastguard Worker""" 96*387f9dfdSAndroid Build Coastguard Worker 97*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_rename_text_old=""" 98*387f9dfdSAndroid Build Coastguard Workerint trace_rename(struct pt_regs *ctx, struct inode *old_dir, struct dentry *old_dentry, 99*387f9dfdSAndroid Build Coastguard Workerstruct inode *new_dir, struct dentry *new_dentry) 100*387f9dfdSAndroid Build Coastguard Worker{ 101*387f9dfdSAndroid Build Coastguard Worker""" 102*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_rename_text_new=""" 103*387f9dfdSAndroid Build Coastguard Workerint trace_rename(struct pt_regs *ctx, struct renamedata *rd) 104*387f9dfdSAndroid Build Coastguard Worker{ 105*387f9dfdSAndroid Build Coastguard Worker struct dentry *old_dentry = rd->old_dentry; 106*387f9dfdSAndroid Build Coastguard Worker struct dentry *new_dentry = rd->new_dentry; 107*387f9dfdSAndroid Build Coastguard Worker""" 108*387f9dfdSAndroid Build Coastguard Worker 109*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_unlink_text_1=""" 110*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry) 111*387f9dfdSAndroid Build Coastguard Worker""" 112*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_unlink_text_2=""" 113*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct user_namespace *ns, struct inode *dir, struct dentry *dentry) 114*387f9dfdSAndroid Build Coastguard Worker""" 115*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_unlink_text_3=""" 116*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry) 117*387f9dfdSAndroid Build Coastguard Worker""" 118*387f9dfdSAndroid Build Coastguard Worker 119*387f9dfdSAndroid Build Coastguard Workerdef action2str(action): 120*387f9dfdSAndroid Build Coastguard Worker if chr(action) == 'D': 121*387f9dfdSAndroid Build Coastguard Worker action_str = "DELETE" 122*387f9dfdSAndroid Build Coastguard Worker else: 123*387f9dfdSAndroid Build Coastguard Worker action_str = "RENAME" 124*387f9dfdSAndroid Build Coastguard Worker return action_str 125*387f9dfdSAndroid Build Coastguard Worker 126*387f9dfdSAndroid Build Coastguard Workerif args.pid: 127*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER', 128*387f9dfdSAndroid Build Coastguard Worker 'if (pid != %s) { return 0; }' % args.pid) 129*387f9dfdSAndroid Build Coastguard Workerelse: 130*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER', '') 131*387f9dfdSAndroid Build Coastguard Worker 132*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 133*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 134*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 135*387f9dfdSAndroid Build Coastguard Worker exit() 136*387f9dfdSAndroid Build Coastguard Worker 137*387f9dfdSAndroid Build Coastguard Worker# check 'struct renamedata' exist or not 138*387f9dfdSAndroid Build Coastguard Workerif BPF.kernel_struct_has_field(b'renamedata', b'new_mnt_idmap') == 1: 139*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TRACE_VFS_RENAME_FUNC', bpf_vfs_rename_text_new) 140*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TRACE_VFS_UNLINK_FUNC', bpf_vfs_unlink_text_3) 141*387f9dfdSAndroid Build Coastguard Workerelif BPF.kernel_struct_has_field("renamedata", "old_mnt_userns") == 1: 142*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TRACE_VFS_RENAME_FUNC', bpf_vfs_rename_text_new) 143*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TRACE_VFS_UNLINK_FUNC', bpf_vfs_unlink_text_2) 144*387f9dfdSAndroid Build Coastguard Workerelse: 145*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TRACE_VFS_RENAME_FUNC', bpf_vfs_rename_text_old) 146*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('TRACE_VFS_UNLINK_FUNC', bpf_vfs_unlink_text_1) 147*387f9dfdSAndroid Build Coastguard Worker 148*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 149*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 150*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_unlink", fn_name="trace_unlink") 151*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_rmdir", fn_name="trace_unlink") 152*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_rename", fn_name="trace_rename") 153*387f9dfdSAndroid Build Coastguard Worker 154*387f9dfdSAndroid Build Coastguard Worker# header 155*387f9dfdSAndroid Build Coastguard Workerprint("%-8s %-7s %-16s %6s %s" % ("TIME", "PID", "COMM", "ACTION", "FILE")) 156*387f9dfdSAndroid Build Coastguard Worker 157*387f9dfdSAndroid Build Coastguard Worker# process event 158*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 159*387f9dfdSAndroid Build Coastguard Worker event = b["events"].event(data) 160*387f9dfdSAndroid Build Coastguard Worker action_str = action2str(event.action) 161*387f9dfdSAndroid Build Coastguard Worker file_str = event.fname.decode('utf-8', 'replace') 162*387f9dfdSAndroid Build Coastguard Worker if action_str == "RENAME": 163*387f9dfdSAndroid Build Coastguard Worker file_str = "%s > %s" % (file_str, event.fname2.decode('utf-8', 'replace')) 164*387f9dfdSAndroid Build Coastguard Worker print("%-8s %-7d %-16s %6s %s" % (strftime("%H:%M:%S"), event.pid, 165*387f9dfdSAndroid Build Coastguard Worker event.comm.decode('utf-8', 'replace'), action_str, file_str)) 166*387f9dfdSAndroid Build Coastguard Worker 167*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event) 168*387f9dfdSAndroid Build Coastguard Workerwhile 1: 169*387f9dfdSAndroid Build Coastguard Worker try: 170*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 171*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 172*387f9dfdSAndroid Build Coastguard Worker exit() 173