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