1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 #include <vmlinux.h>
3 #include <bpf/bpf_helpers.h>
4 #include <bpf/bpf_core_read.h>
5 #include "execsnoop.h"
6
7 const volatile bool filter_cg = false;
8 const volatile bool ignore_failed = true;
9 const volatile uid_t targ_uid = INVALID_UID;
10 const volatile int max_args = DEFAULT_MAXARGS;
11
12 static const struct event empty_event = {};
13
14 struct {
15 __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
16 __type(key, u32);
17 __type(value, u32);
18 __uint(max_entries, 1);
19 } cgroup_map SEC(".maps");
20
21 struct {
22 __uint(type, BPF_MAP_TYPE_HASH);
23 __uint(max_entries, 10240);
24 __type(key, pid_t);
25 __type(value, struct event);
26 } execs SEC(".maps");
27
28 struct {
29 __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
30 __uint(key_size, sizeof(u32));
31 __uint(value_size, sizeof(u32));
32 } events SEC(".maps");
33
valid_uid(uid_t uid)34 static __always_inline bool valid_uid(uid_t uid) {
35 return uid != INVALID_UID;
36 }
37
38 SEC("tracepoint/syscalls/sys_enter_execve")
tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter * ctx)39 int tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter* ctx)
40 {
41 u64 id;
42 pid_t pid, tgid;
43 int ret;
44 struct event *event;
45 struct task_struct *task;
46 const char **args = (const char **)(ctx->args[1]);
47 const char *argp;
48
49 if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
50 return 0;
51
52 uid_t uid = (u32)bpf_get_current_uid_gid();
53 int i;
54
55 if (valid_uid(targ_uid) && targ_uid != uid)
56 return 0;
57
58 id = bpf_get_current_pid_tgid();
59 pid = (pid_t)id;
60 tgid = id >> 32;
61 if (bpf_map_update_elem(&execs, &pid, &empty_event, BPF_NOEXIST))
62 return 0;
63
64 event = bpf_map_lookup_elem(&execs, &pid);
65 if (!event)
66 return 0;
67
68 event->pid = tgid;
69 event->uid = uid;
70 task = (struct task_struct*)bpf_get_current_task();
71 event->ppid = (pid_t)BPF_CORE_READ(task, real_parent, tgid);
72 event->args_count = 0;
73 event->args_size = 0;
74
75 ret = bpf_probe_read_user_str(event->args, ARGSIZE, (const char*)ctx->args[0]);
76 if (ret < 0) {
77 return 0;
78 }
79 if (ret <= ARGSIZE) {
80 event->args_size += ret;
81 } else {
82 /* write an empty string */
83 event->args[0] = '\0';
84 event->args_size++;
85 }
86
87 event->args_count++;
88 #pragma unroll
89 for (i = 1; i < TOTAL_MAX_ARGS && i < max_args; i++) {
90 ret = bpf_probe_read_user(&argp, sizeof(argp), &args[i]);
91 if (ret < 0)
92 return 0;
93
94 if (event->args_size > LAST_ARG)
95 return 0;
96
97 ret = bpf_probe_read_user_str(&event->args[event->args_size], ARGSIZE, argp);
98 if (ret < 0)
99 return 0;
100
101 event->args_count++;
102 event->args_size += ret;
103 }
104 /* try to read one more argument to check if there is one */
105 ret = bpf_probe_read_user(&argp, sizeof(argp), &args[max_args]);
106 if (ret < 0)
107 return 0;
108
109 /* pointer to max_args+1 isn't null, asume we have more arguments */
110 event->args_count++;
111 return 0;
112 }
113
114 SEC("tracepoint/syscalls/sys_exit_execve")
tracepoint__syscalls__sys_exit_execve(struct trace_event_raw_sys_exit * ctx)115 int tracepoint__syscalls__sys_exit_execve(struct trace_event_raw_sys_exit* ctx)
116 {
117 u64 id;
118 pid_t pid;
119 int ret;
120 struct event *event;
121
122 if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
123 return 0;
124
125 u32 uid = (u32)bpf_get_current_uid_gid();
126
127 if (valid_uid(targ_uid) && targ_uid != uid)
128 return 0;
129 id = bpf_get_current_pid_tgid();
130 pid = (pid_t)id;
131 event = bpf_map_lookup_elem(&execs, &pid);
132 if (!event)
133 return 0;
134 ret = ctx->ret;
135 if (ignore_failed && ret < 0)
136 goto cleanup;
137
138 event->retval = ret;
139 bpf_get_current_comm(&event->comm, sizeof(event->comm));
140 size_t len = EVENT_SIZE(event);
141 if (len <= sizeof(*event))
142 bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, len);
143 cleanup:
144 bpf_map_delete_elem(&execs, &pid);
145 return 0;
146 }
147
148 char LICENSE[] SEC("license") = "GPL";
149