Skip to content

Commit

Permalink
tools: filelife: Check btf struct field for CO-RE and add vfs_open()
Browse files Browse the repository at this point in the history
Since kernel commit 6521f8917082("namei: prepare for idmapped mounts"),
the vfs_unlink/create function add argument 'struct user_namespace'. And
add vfs_open() probe if 'f_mode = FMODE_CREATED'. In the same commit,
'struct renamedata' add 'old_mnt_userns' field, use 'old_mnt_userns' to
determine which function to use.

Signed-off-by: Rong Tao <[email protected]>
  • Loading branch information
Rtoax authored and yonghong-song committed Nov 27, 2022
1 parent ebb47d5 commit 921b736
Showing 1 changed file with 56 additions and 6 deletions.
62 changes: 56 additions & 6 deletions tools/filelife.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#
# 08-Feb-2015 Brendan Gregg Created this.
# 17-Feb-2016 Allan McAleavy updated for BPF_PERF_OUTPUT
# 13-Nov-2022 Rong Tao Check btf struct field for CO-RE and add vfs_open()

from __future__ import print_function
from bcc import BPF
Expand All @@ -24,11 +25,11 @@

# arguments
examples = """examples:
./filelife # trace all stat() syscalls
./filelife # trace lifecycle of file(create->remove)
./filelife -p 181 # only trace PID 181
"""
parser = argparse.ArgumentParser(
description="Trace stat() syscalls",
description="Trace lifecycle of file",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples)
parser.add_argument("-p", "--pid",
Expand All @@ -54,8 +55,7 @@
BPF_HASH(birth, struct dentry *);
BPF_PERF_OUTPUT(events);
// trace file creation time
int trace_create(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
static int probe_dentry(struct pt_regs *ctx, struct dentry *dentry)
{
u32 pid = bpf_get_current_pid_tgid() >> 32;
FILTER
Expand All @@ -64,10 +64,35 @@
birth.update(&dentry, &ts);
return 0;
}
// trace file creation time
TRACE_CREATE_FUNC
{
return probe_dentry(ctx, dentry);
};
// trace file security_inode_create time
int trace_security_inode_create(struct pt_regs *ctx, struct inode *dir,
struct dentry *dentry)
{
return probe_dentry(ctx, dentry);
};
// trace file open time
int trace_open(struct pt_regs *ctx, struct path *path, struct file *file)
{
struct dentry *dentry = path->dentry;
if (!(file->f_mode & FMODE_CREATED)) {
return 0;
}
return probe_dentry(ctx, dentry);
};
// trace file deletion and output details
int trace_unlink(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
TRACE_UNLINK_FUNC
{
struct data_t data = {};
u32 pid = bpf_get_current_pid_tgid() >> 32;
Expand Down Expand Up @@ -99,6 +124,22 @@
}
"""

trace_create_text_old="""
int trace_create(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
"""
trace_create_text_new="""
int trace_create(struct pt_regs *ctx, struct user_namespace *mnt_userns,
struct inode *dir, struct dentry *dentry)
"""

trace_unlink_text_old="""
int trace_unlink(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
"""
trace_unlink_text_new="""
int trace_unlink(struct pt_regs *ctx, struct user_namespace *mnt_userns,
struct inode *dir, struct dentry *dentry)
"""

if args.pid:
bpf_text = bpf_text.replace('FILTER',
'if (pid != %s) { return 0; }' % args.pid)
Expand All @@ -109,12 +150,21 @@
if args.ebpf:
exit()

if BPF.kernel_struct_has_field(b'renamedata', b'old_mnt_userns') == 1:
bpf_text = bpf_text.replace('TRACE_CREATE_FUNC', trace_create_text_new)
bpf_text = bpf_text.replace('TRACE_UNLINK_FUNC', trace_unlink_text_new)
else:
bpf_text = bpf_text.replace('TRACE_CREATE_FUNC', trace_create_text_old)
bpf_text = bpf_text.replace('TRACE_UNLINK_FUNC', trace_unlink_text_old)

# initialize BPF
b = BPF(text=bpf_text)
b.attach_kprobe(event="vfs_create", fn_name="trace_create")
# newer kernels may don't fire vfs_create, call vfs_open instead:
b.attach_kprobe(event="vfs_open", fn_name="trace_open")
# newer kernels (say, 4.8) may don't fire vfs_create, so record (or overwrite)
# the timestamp in security_inode_create():
b.attach_kprobe(event="security_inode_create", fn_name="trace_create")
b.attach_kprobe(event="security_inode_create", fn_name="trace_security_inode_create")
b.attach_kprobe(event="vfs_unlink", fn_name="trace_unlink")

# header
Expand Down

0 comments on commit 921b736

Please sign in to comment.