|
24 | 24 | import argparse |
25 | 25 | import re |
26 | 26 | import time |
| 27 | +import pwd |
27 | 28 | from collections import defaultdict |
28 | 29 | from time import strftime |
29 | 30 |
|
| 31 | + |
| 32 | +def parse_uid(user): |
| 33 | + try: |
| 34 | + result = int(user) |
| 35 | + except ValueError: |
| 36 | + try: |
| 37 | + user_info = pwd.getpwnam(user) |
| 38 | + except KeyError: |
| 39 | + raise argparse.ArgumentTypeError( |
| 40 | + "{0!r} is not valid UID or user entry".format(user)) |
| 41 | + else: |
| 42 | + return user_info.pw_uid |
| 43 | + else: |
| 44 | + # Maybe validate if UID < 0 ? |
| 45 | + return result |
| 46 | + |
| 47 | + |
30 | 48 | # arguments |
31 | 49 | examples = """examples: |
32 | 50 | ./execsnoop # trace all exec() syscalls |
33 | 51 | ./execsnoop -x # include failed exec()s |
34 | 52 | ./execsnoop -T # include time (HH:MM:SS) |
| 53 | + ./execsnoop -U # include UID |
| 54 | + ./execsnoop -u 1000 # only trace UID 1000 |
| 55 | + ./execsnoop -u user # get user UID and trace only them |
35 | 56 | ./execsnoop -t # include timestamps |
36 | 57 | ./execsnoop -q # add "quotemarks" around arguments |
37 | 58 | ./execsnoop -n main # only print command lines containing "main" |
|
50 | 71 | help="include failed exec()s") |
51 | 72 | parser.add_argument("--cgroupmap", |
52 | 73 | help="trace cgroups in this BPF map only") |
| 74 | +parser.add_argument("-u", "--uid", type=parse_uid, metavar='USER', |
| 75 | + help="trace this UID only") |
53 | 76 | parser.add_argument("-q", "--quote", action="store_true", |
54 | 77 | help="Add quotemarks (\") around arguments." |
55 | 78 | ) |
|
59 | 82 | parser.add_argument("-l", "--line", |
60 | 83 | type=ArgString, |
61 | 84 | help="only print commands where arg contains this line (regex)") |
| 85 | +parser.add_argument("-U", "--print-uid", action="store_true", |
| 86 | + help="print UID column") |
62 | 87 | parser.add_argument("--max-args", default="20", |
63 | 88 | help="maximum number of arguments parsed and displayed, defaults to 20") |
64 | 89 | parser.add_argument("--ebpf", action="store_true", |
|
81 | 106 | struct data_t { |
82 | 107 | u32 pid; // PID as in the userspace term (i.e. task->tgid in kernel) |
83 | 108 | u32 ppid; // Parent PID as in the userspace term (i.e task->real_parent->tgid in kernel) |
| 109 | + u32 uid; |
84 | 110 | char comm[TASK_COMM_LEN]; |
85 | 111 | enum event_type type; |
86 | 112 | char argv[ARGSIZE]; |
|
114 | 140 | const char __user *const __user *__argv, |
115 | 141 | const char __user *const __user *__envp) |
116 | 142 | { |
| 143 | +
|
| 144 | + u32 uid = bpf_get_current_uid_gid() & 0xffffffff; |
| 145 | +
|
| 146 | + UID_FILTER |
| 147 | +
|
117 | 148 | #if CGROUPSET |
118 | 149 | u64 cgroupid = bpf_get_current_cgroup_id(); |
119 | 150 | if (cgroupset.lookup(&cgroupid) == NULL) { |
|
164 | 195 | struct data_t data = {}; |
165 | 196 | struct task_struct *task; |
166 | 197 |
|
| 198 | + u32 uid = bpf_get_current_uid_gid() & 0xffffffff; |
| 199 | + UID_FILTER |
| 200 | +
|
167 | 201 | data.pid = bpf_get_current_pid_tgid() >> 32; |
| 202 | + data.uid = uid; |
168 | 203 |
|
169 | 204 | task = (struct task_struct *)bpf_get_current_task(); |
170 | 205 | // Some kernels, like Ubuntu 4.13.0-generic, return 0 |
|
182 | 217 | """ |
183 | 218 |
|
184 | 219 | bpf_text = bpf_text.replace("MAXARG", args.max_args) |
| 220 | + |
| 221 | +if args.uid: |
| 222 | + bpf_text = bpf_text.replace('UID_FILTER', |
| 223 | + 'if (uid != %s) { return 0; }' % args.uid) |
| 224 | +else: |
| 225 | + bpf_text = bpf_text.replace('UID_FILTER', '') |
185 | 226 | if args.cgroupmap: |
186 | 227 | bpf_text = bpf_text.replace('CGROUPSET', '1') |
187 | 228 | bpf_text = bpf_text.replace('CGROUPPATH', args.cgroupmap) |
|
202 | 243 | print("%-9s" % ("TIME"), end="") |
203 | 244 | if args.timestamp: |
204 | 245 | print("%-8s" % ("TIME(s)"), end="") |
| 246 | +if args.print_uid: |
| 247 | + print("%-6s" % ("UID"), end="") |
205 | 248 | print("%-16s %-6s %-6s %3s %s" % ("PCOMM", "PID", "PPID", "RET", "ARGS")) |
206 | 249 |
|
207 | 250 | class EventType(object): |
@@ -251,6 +294,8 @@ def print_event(cpu, data, size): |
251 | 294 | printb(b"%-9s" % strftime("%H:%M:%S").encode('ascii'), nl="") |
252 | 295 | if args.timestamp: |
253 | 296 | printb(b"%-8.3f" % (time.time() - start_ts), nl="") |
| 297 | + if args.print_uid: |
| 298 | + printb(b"%-6d" % event.uid, nl="") |
254 | 299 | ppid = event.ppid if event.ppid > 0 else get_ppid(event.pid) |
255 | 300 | ppid = b"%d" % ppid if ppid > 0 else b"?" |
256 | 301 | argv_text = b' '.join(argv[event.pid]).replace(b'\n', b'\\n') |
|
0 commit comments