1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2021 Hengqi Chen
3 #include <vmlinux.h>
4 #include <bpf/bpf_helpers.h>
5 #include <bpf/bpf_tracing.h>
6 #include "statsnoop.h"
7
8 #define MAX_ENTRIES 10240
9
10 const volatile pid_t target_pid = 0;
11 const volatile bool trace_failed_only = false;
12
13 struct {
14 __uint(type, BPF_MAP_TYPE_HASH);
15 __uint(max_entries, MAX_ENTRIES);
16 __type(key, __u32);
17 __type(value, const char *);
18 } values SEC(".maps");
19
20 struct {
21 __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
22 __uint(key_size, sizeof(__u32));
23 __uint(value_size, sizeof(__u32));
24 } events SEC(".maps");
25
probe_entry(void * ctx,const char * pathname)26 static int probe_entry(void *ctx, const char *pathname)
27 {
28 __u64 id = bpf_get_current_pid_tgid();
29 __u32 pid = id >> 32;
30 __u32 tid = (__u32)id;
31
32 if (!pathname)
33 return 0;
34
35 if (target_pid && target_pid != pid)
36 return 0;
37
38 bpf_map_update_elem(&values, &tid, &pathname, BPF_ANY);
39 return 0;
40 };
41
probe_return(void * ctx,int ret)42 static int probe_return(void *ctx, int ret)
43 {
44 __u64 id = bpf_get_current_pid_tgid();
45 __u32 pid = id >> 32;
46 __u32 tid = (__u32)id;
47 const char **pathname;
48 struct event event = {};
49
50 pathname = bpf_map_lookup_elem(&values, &tid);
51 if (!pathname)
52 return 0;
53
54 if (trace_failed_only && ret >= 0) {
55 bpf_map_delete_elem(&values, &tid);
56 return 0;
57 }
58
59 event.pid = pid;
60 event.ts_ns = bpf_ktime_get_ns();
61 event.ret = ret;
62 bpf_get_current_comm(&event.comm, sizeof(event.comm));
63 bpf_probe_read_user_str(event.pathname, sizeof(event.pathname), *pathname);
64
65 bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));
66 bpf_map_delete_elem(&values, &tid);
67 return 0;
68 }
69
70 SEC("tracepoint/syscalls/sys_enter_statfs")
handle_statfs_entry(struct trace_event_raw_sys_enter * ctx)71 int handle_statfs_entry(struct trace_event_raw_sys_enter *ctx)
72 {
73 return probe_entry(ctx, (const char *)ctx->args[0]);
74 }
75
76 SEC("tracepoint/syscalls/sys_exit_statfs")
handle_statfs_return(struct trace_event_raw_sys_exit * ctx)77 int handle_statfs_return(struct trace_event_raw_sys_exit *ctx)
78 {
79 return probe_return(ctx, (int)ctx->ret);
80 }
81
82 SEC("tracepoint/syscalls/sys_enter_newstat")
handle_newstat_entry(struct trace_event_raw_sys_enter * ctx)83 int handle_newstat_entry(struct trace_event_raw_sys_enter *ctx)
84 {
85 return probe_entry(ctx, (const char *)ctx->args[0]);
86 }
87
88 SEC("tracepoint/syscalls/sys_exit_newstat")
handle_newstat_return(struct trace_event_raw_sys_exit * ctx)89 int handle_newstat_return(struct trace_event_raw_sys_exit *ctx)
90 {
91 return probe_return(ctx, (int)ctx->ret);
92 }
93
94 SEC("tracepoint/syscalls/sys_enter_statx")
handle_statx_entry(struct trace_event_raw_sys_enter * ctx)95 int handle_statx_entry(struct trace_event_raw_sys_enter *ctx)
96 {
97 return probe_entry(ctx, (const char *)ctx->args[1]);
98 }
99
100 SEC("tracepoint/syscalls/sys_exit_statx")
handle_statx_return(struct trace_event_raw_sys_exit * ctx)101 int handle_statx_return(struct trace_event_raw_sys_exit *ctx)
102 {
103 return probe_return(ctx, (int)ctx->ret);
104 }
105
106 SEC("tracepoint/syscalls/sys_enter_newfstatat")
handle_newfstatat_entry(struct trace_event_raw_sys_enter * ctx)107 int handle_newfstatat_entry(struct trace_event_raw_sys_enter *ctx)
108 {
109 return probe_entry(ctx, (const char *)ctx->args[1]);
110 }
111
112 SEC("tracepoint/syscalls/sys_exit_newfstatat")
handle_newfstatat_return(struct trace_event_raw_sys_exit * ctx)113 int handle_newfstatat_return(struct trace_event_raw_sys_exit *ctx)
114 {
115 return probe_return(ctx, (int)ctx->ret);
116 }
117
118 SEC("tracepoint/syscalls/sys_enter_newlstat")
handle_newlstat_entry(struct trace_event_raw_sys_enter * ctx)119 int handle_newlstat_entry(struct trace_event_raw_sys_enter *ctx)
120 {
121 return probe_entry(ctx, (const char *)ctx->args[0]);
122 }
123
124 SEC("tracepoint/syscalls/sys_exit_newlstat")
handle_newlstat_return(struct trace_event_raw_sys_exit * ctx)125 int handle_newlstat_return(struct trace_event_raw_sys_exit *ctx)
126 {
127 return probe_return(ctx, (int)ctx->ret);
128 }
129
130 char LICENSE[] SEC("license") = "GPL";
131