Skip to content

Commit

Permalink
tools/opensnoop: Snoop all open related syscall stubs
Browse files Browse the repository at this point in the history
kernel v5.6 introduces fddb5d430ad9 ("open: introduce openat2(2) syscall").
Even though do_sys_open still exists, it might be optimized off final binary
depending on compilers. So we can't catch do_sys_open in some cases.

This patch uses ksymname to try to get entries of open, openat and openat2,
and changes the definitions of the trace functions to snoop them all. This
works for both kprobe and kfunc.

Credit to Yonghong Song for better code organization.

Signed-off-by: He Zhe <[email protected]>
  • Loading branch information
He Zhe authored and yonghong-song committed Jul 23, 2020
1 parent ba0bacf commit 6889afe
Showing 1 changed file with 119 additions and 30 deletions.
149 changes: 119 additions & 30 deletions tools/opensnoop.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,52 @@
bpf_text_kprobe = """
BPF_HASH(infotmp, u64, struct val_t);
int trace_entry(struct pt_regs *ctx, int dfd, const char __user *filename, int flags)
int trace_return(struct pt_regs *ctx)
{
u64 id = bpf_get_current_pid_tgid();
struct val_t *valp;
struct data_t data = {};
u64 tsp = bpf_ktime_get_ns();
valp = infotmp.lookup(&id);
if (valp == 0) {
// missed entry
return 0;
}
bpf_probe_read_kernel(&data.comm, sizeof(data.comm), valp->comm);
bpf_probe_read_user(&data.fname, sizeof(data.fname), (void *)valp->fname);
data.id = valp->id;
data.ts = tsp / 1000;
data.uid = bpf_get_current_uid_gid();
data.flags = valp->flags; // EXTENDED_STRUCT_MEMBER
data.ret = PT_REGS_RC(ctx);
events.perf_submit(ctx, &data, sizeof(data));
infotmp.delete(&id);
return 0;
}
"""

bpf_text_kprobe_header_open = """
int syscall__trace_entry_open(struct pt_regs *ctx, const char __user *filename, int flags)
{
"""

bpf_text_kprobe_header_openat = """
int syscall__trace_entry_openat(struct pt_regs *ctx, int dfd, const char __user *filename, int flags)
{
"""

bpf_text_kprobe_header_openat2 = """
#include <uapi/linux/openat2.h>
int syscall__trace_entry_openat2(struct pt_regs *ctx, int dfd, const char __user *filename, struct open_how *how)
{
int flags = how->flags;
"""

bpf_text_kprobe_body = """
struct val_t val = {};
u64 id = bpf_get_current_pid_tgid();
u32 pid = id >> 32; // PID is higher part
Expand All @@ -137,38 +181,50 @@
return 0;
};
"""

int trace_return(struct pt_regs *ctx)
bpf_text_kfunc_header_open = """
#if defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) && !defined(__s390x__)
KRETFUNC_PROBE(FNNAME, struct pt_regs *regs, int ret)
{
u64 id = bpf_get_current_pid_tgid();
struct val_t *valp;
struct data_t data = {};
u64 tsp = bpf_ktime_get_ns();
valp = infotmp.lookup(&id);
if (valp == 0) {
// missed entry
return 0;
}
bpf_probe_read_kernel(&data.comm, sizeof(data.comm), valp->comm);
bpf_probe_read_user(&data.fname, sizeof(data.fname), (void *)valp->fname);
data.id = valp->id;
data.ts = tsp / 1000;
data.uid = bpf_get_current_uid_gid();
data.flags = valp->flags; // EXTENDED_STRUCT_MEMBER
data.ret = PT_REGS_RC(ctx);
events.perf_submit(ctx, &data, sizeof(data));
infotmp.delete(&id);
const char __user *filename = (char *)PT_REGS_PARM1(regs);
int flags = PT_REGS_PARM2(regs);
#else
KRETFUNC_PROBE(FNNAME, const char __user *filename, int flags, int ret)
{
#endif
"""

return 0;
}
bpf_text_kfunc_header_openat = """
#if defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) && !defined(__s390x__)
KRETFUNC_PROBE(FNNAME, struct pt_regs *regs, int ret)
{
int dfd = PT_REGS_PARM1(regs);
const char __user *filename = (char *)PT_REGS_PARM2(regs);
int flags = PT_REGS_PARM3(regs);
#else
KRETFUNC_PROBE(FNNAME, int dfd, const char __user *filename, int flags, int ret)
{
#endif
"""

bpf_text_kfunc= """
KRETFUNC_PROBE(do_sys_open, int dfd, const char __user *filename, int flags, int mode, int ret)
bpf_text_kfunc_header_openat2 = """
#include <uapi/linux/openat2.h>
#if defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) && !defined(__s390x__)
KRETFUNC_PROBE(FNNAME, struct pt_regs *regs, int ret)
{
int dfd = PT_REGS_PARM1(regs);
const char __user *filename = (char *)PT_REGS_PARM2(regs);
struct open_how __user *how = (struct open_how *)PT_REGS_PARM3(regs);
int flags = how->flags;
#else
KRETFUNC_PROBE(FNNAME, int dfd, const char __user *filename, struct open_how __user *how, int ret)
{
int flags = how->flags;
#endif
"""

bpf_text_kfunc_body = """
u64 id = bpf_get_current_pid_tgid();
u32 pid = id >> 32; // PID is higher part
u32 tid = id; // Cast and get the lower part
Expand Down Expand Up @@ -199,12 +255,38 @@
}
"""

b = BPF(text='')
# open and openat are always in place since 2.6.16
fnname_open = b.get_syscall_prefix().decode() + 'open'
fnname_openat = b.get_syscall_prefix().decode() + 'openat'
fnname_openat2 = b.get_syscall_prefix().decode() + 'openat2'
if b.ksymname(fnname_openat2) == -1:
fnname_openat2 = None

is_support_kfunc = BPF.support_kfunc()
if is_support_kfunc:
bpf_text += bpf_text_kfunc
bpf_text += bpf_text_kfunc_header_open.replace('FNNAME', fnname_open)
bpf_text += bpf_text_kfunc_body

bpf_text += bpf_text_kfunc_header_openat.replace('FNNAME', fnname_openat)
bpf_text += bpf_text_kfunc_body

if fnname_openat2:
bpf_text += bpf_text_kfunc_header_openat2.replace('FNNAME', fnname_openat2)
bpf_text += bpf_text_kfunc_body
else:
bpf_text += bpf_text_kprobe

bpf_text += bpf_text_kprobe_header_open
bpf_text += bpf_text_kprobe_body

bpf_text += bpf_text_kprobe_header_openat
bpf_text += bpf_text_kprobe_body

if fnname_openat2:
bpf_text += bpf_text_kprobe_header_openat2
bpf_text += bpf_text_kprobe_body

if args.tid: # TID trumps PID
bpf_text = bpf_text.replace('PID_TID_FILTER',
'if (tid != %s) { return 0; }' % args.tid)
Expand Down Expand Up @@ -235,8 +317,15 @@
# initialize BPF
b = BPF(text=bpf_text)
if not is_support_kfunc:
b.attach_kprobe(event="do_sys_open", fn_name="trace_entry")
b.attach_kretprobe(event="do_sys_open", fn_name="trace_return")
b.attach_kprobe(event=fnname_open, fn_name="syscall__trace_entry_open")
b.attach_kretprobe(event=fnname_open, fn_name="trace_return")

b.attach_kprobe(event=fnname_openat, fn_name="syscall__trace_entry_openat")
b.attach_kretprobe(event=fnname_openat, fn_name="trace_return")

if fnname_openat2:
b.attach_kprobe(event=fnname_openat2, fn_name="syscall__trace_entry_openat2")
b.attach_kretprobe(event=fnname_openat2, fn_name="trace_return")

initial_ts = 0

Expand Down

0 comments on commit 6889afe

Please sign in to comment.