Skip to content

Commit c949f61

Browse files
bacher09yonghong-song
authored andcommitted
tools: execsnoop add -U and -u flags
Add flags to display UID and filter by UID
1 parent 788bc29 commit c949f61

3 files changed

Lines changed: 99 additions & 4 deletions

File tree

man/man8/execsnoop.8

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
.SH NAME
33
execsnoop \- Trace new processes via exec() syscalls. Uses Linux eBPF/bcc.
44
.SH SYNOPSIS
5-
.B execsnoop [\-h] [\-T] [\-t] [\-x] [\-q] [\-n NAME] [\-l LINE]
6-
.B [\-\-max-args MAX_ARGS] [\-\-cgroupmap MAPPATH]
5+
.B execsnoop [\-h] [\-T] [\-t] [\-x] [\-\-cgroupmap CGROUPMAP] [\-u USER]
6+
.B [\-q] [\-n NAME] [\-l LINE] [\-U] [\-\-max-args MAX_ARGS]
77
.SH DESCRIPTION
88
execsnoop traces new processes, showing the filename executed and argument
99
list.
@@ -28,9 +28,15 @@ Print usage message.
2828
\-T
2929
Include a time column (HH:MM:SS).
3030
.TP
31+
\-U
32+
Include UID column.
33+
.TP
3134
\-t
3235
Include a timestamp column.
3336
.TP
37+
\-u USER
38+
Filter by UID (or username)
39+
.TP
3440
\-x
3541
Include failed exec()s
3642
.TP
@@ -59,6 +65,18 @@ Trace all exec() syscalls, and include timestamps:
5965
#
6066
.B execsnoop \-t
6167
.TP
68+
Display process UID:
69+
#
70+
.B execsnoop \-U
71+
.TP
72+
Trace only UID 1000:
73+
#
74+
.B execsnoop \-u 1000
75+
.TP
76+
Trace only processes launched by root and display UID column:
77+
#
78+
.B execsnoop \-Uu root
79+
.TP
6280
Include failed exec()s:
6381
#
6482
.B execsnoop \-x
@@ -86,6 +104,9 @@ Time of exec() return, in HH:MM:SS format.
86104
TIME(s)
87105
Time of exec() return, in seconds.
88106
.TP
107+
UID
108+
User ID
109+
.TP
89110
PCOMM
90111
Parent process/command name.
91112
.TP

tools/execsnoop.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,35 @@
2424
import argparse
2525
import re
2626
import time
27+
import pwd
2728
from collections import defaultdict
2829
from time import strftime
2930

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+
3048
# arguments
3149
examples = """examples:
3250
./execsnoop # trace all exec() syscalls
3351
./execsnoop -x # include failed exec()s
3452
./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
3556
./execsnoop -t # include timestamps
3657
./execsnoop -q # add "quotemarks" around arguments
3758
./execsnoop -n main # only print command lines containing "main"
@@ -50,6 +71,8 @@
5071
help="include failed exec()s")
5172
parser.add_argument("--cgroupmap",
5273
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")
5376
parser.add_argument("-q", "--quote", action="store_true",
5477
help="Add quotemarks (\") around arguments."
5578
)
@@ -59,6 +82,8 @@
5982
parser.add_argument("-l", "--line",
6083
type=ArgString,
6184
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")
6287
parser.add_argument("--max-args", default="20",
6388
help="maximum number of arguments parsed and displayed, defaults to 20")
6489
parser.add_argument("--ebpf", action="store_true",
@@ -81,6 +106,7 @@
81106
struct data_t {
82107
u32 pid; // PID as in the userspace term (i.e. task->tgid in kernel)
83108
u32 ppid; // Parent PID as in the userspace term (i.e task->real_parent->tgid in kernel)
109+
u32 uid;
84110
char comm[TASK_COMM_LEN];
85111
enum event_type type;
86112
char argv[ARGSIZE];
@@ -114,6 +140,11 @@
114140
const char __user *const __user *__argv,
115141
const char __user *const __user *__envp)
116142
{
143+
144+
u32 uid = bpf_get_current_uid_gid() & 0xffffffff;
145+
146+
UID_FILTER
147+
117148
#if CGROUPSET
118149
u64 cgroupid = bpf_get_current_cgroup_id();
119150
if (cgroupset.lookup(&cgroupid) == NULL) {
@@ -164,7 +195,11 @@
164195
struct data_t data = {};
165196
struct task_struct *task;
166197
198+
u32 uid = bpf_get_current_uid_gid() & 0xffffffff;
199+
UID_FILTER
200+
167201
data.pid = bpf_get_current_pid_tgid() >> 32;
202+
data.uid = uid;
168203
169204
task = (struct task_struct *)bpf_get_current_task();
170205
// Some kernels, like Ubuntu 4.13.0-generic, return 0
@@ -182,6 +217,12 @@
182217
"""
183218

184219
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', '')
185226
if args.cgroupmap:
186227
bpf_text = bpf_text.replace('CGROUPSET', '1')
187228
bpf_text = bpf_text.replace('CGROUPPATH', args.cgroupmap)
@@ -202,6 +243,8 @@
202243
print("%-9s" % ("TIME"), end="")
203244
if args.timestamp:
204245
print("%-8s" % ("TIME(s)"), end="")
246+
if args.print_uid:
247+
print("%-6s" % ("UID"), end="")
205248
print("%-16s %-6s %-6s %3s %s" % ("PCOMM", "PID", "PPID", "RET", "ARGS"))
206249

207250
class EventType(object):
@@ -251,6 +294,8 @@ def print_event(cpu, data, size):
251294
printb(b"%-9s" % strftime("%H:%M:%S").encode('ascii'), nl="")
252295
if args.timestamp:
253296
printb(b"%-8.3f" % (time.time() - start_ts), nl="")
297+
if args.print_uid:
298+
printb(b"%-6d" % event.uid, nl="")
254299
ppid = event.ppid if event.ppid > 0 else get_ppid(event.pid)
255300
ppid = b"%d" % ppid if ppid > 0 else b"?"
256301
argv_text = b' '.join(argv[event.pid]).replace(b'\n', b'\\n')

tools/execsnoop_example.txt

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,32 @@ with an externally created map.
8585

8686
For more details, see docs/filtering_by_cgroups.md
8787

88+
The -U option include UID on output:
89+
90+
# ./execsnoop -U
91+
92+
UID PCOMM PID PPID RET ARGS
93+
1000 ls 171318 133702 0 /bin/ls --color=auto
94+
1000 w 171322 133702 0 /usr/bin/w
95+
96+
The -u options filters output based process UID. You also can use username as
97+
argument, in that cause UID will be looked up using getpwnam (see man 3 getpwnam).
98+
99+
# ./execsnoop -Uu 1000
100+
UID PCOMM PID PPID RET ARGS
101+
1000 ls 171335 133702 0 /bin/ls --color=auto
102+
1000 man 171340 133702 0 /usr/bin/man getpwnam
103+
1000 bzip2 171341 171340 0 /bin/bzip2 -dc
104+
1000 bzip2 171342 171340 0 /bin/bzip2 -dc
105+
1000 bzip2 171345 171340 0 /bin/bzip2 -dc
106+
1000 manpager 171355 171340 0 /usr/bin/manpager
107+
1000 less 171355 171340 0 /usr/bin/less
88108

89109
USAGE message:
90110

91111
# ./execsnoop -h
92-
usage: execsnoop [-h] [-T] [-t] [-x] [-q] [-n NAME] [-l LINE] [--max-args MAX_ARGS]
112+
usage: execsnoop.py [-h] [-T] [-t] [-x] [--cgroupmap CGROUPMAP] [-u USER] [-q]
113+
[-n NAME] [-l LINE] [-U] [--max-args MAX_ARGS]
93114

94115
Trace exec() syscalls
95116

@@ -98,19 +119,27 @@ optional arguments:
98119
-T, --time include time column on output (HH:MM:SS)
99120
-t, --timestamp include timestamp on output
100121
-x, --fails include failed exec()s
101-
-q, --quote Add quotemarks (") around arguments
122+
--cgroupmap CGROUPMAP
123+
trace cgroups in this BPF map only
124+
-u USER, --uid USER trace this UID only
125+
-q, --quote Add quotemarks (") around arguments.
102126
-n NAME, --name NAME only print commands matching this name (regex), any
103127
arg
104128
-l LINE, --line LINE only print commands where arg contains this line
105129
(regex)
130+
-U, --print-uid print UID column
106131
--max-args MAX_ARGS maximum number of arguments parsed and displayed,
107132
defaults to 20
108133

109134
examples:
110135
./execsnoop # trace all exec() syscalls
111136
./execsnoop -x # include failed exec()s
112137
./execsnoop -T # include time (HH:MM:SS)
138+
./execsnoop -U # include UID
139+
./execsnoop -u 1000 # only trace UID 1000
140+
./execsnoop -u root # get root UID and trace only this
113141
./execsnoop -t # include timestamps
114142
./execsnoop -q # add "quotemarks" around arguments
115143
./execsnoop -n main # only print command lines containing "main"
116144
./execsnoop -l tpkg # only print command where arguments contains "tpkg"
145+
./execsnoop --cgroupmap ./mappath # only trace cgroups in this BPF map

0 commit comments

Comments
 (0)