Skip to content

Commit d41bfa5

Browse files
kanurag94anurag
and
anurag
authored
comments; sanity
Co-authored-by: anurag <[email protected]>
1 parent 5468cff commit d41bfa5

File tree

4 files changed

+65
-18
lines changed

4 files changed

+65
-18
lines changed

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@
33
ebpf based Filemonitoring
44

55
```
6-
usage: filemonitor.py [-h] [-f FILE]
6+
usage: filemonitor.py [-h] [-f FILE] [-r] [-w] [-p] [-c] [-d]
77
88
Monitors file actions
99
1010
optional arguments:
1111
-h, --help show this help message and exit
1212
-f FILE, --file FILE give config filepath
13+
-r, --read trace read events
14+
-w, --write trace write events
15+
-p, --rename trace rename events
16+
-c, --create trace create events
17+
-d, --delete trace delete events
1318
14-
Usage:
15-
./filemonitor # traces /var/log/syslog
16-
./filemonitor -f /path/to/config # pass a file with new line separated filepaths to monitor
19+
Example:
20+
./filemonitor -r # traces read of /var/log/syslog
21+
./filemonitor -f /path/to/config # traces filepaths in path for all events
22+
./filemonitor -f /path/to/config -d # traces filepaths in path for delete events
1723
```

cli.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import argparse
22
from distutils.command.config import config
33

4+
# sample_config traces /var/log/syslog
45
sample_config = "config.txt"
56

67
try:
@@ -9,12 +10,24 @@
910
except:
1011
pass
1112

12-
examples = """Usage:
13-
./filemonitor # traces /var/log/syslog
14-
./filemonitor -f /path/to/config # pass a file with new line separated filepaths to monitor
13+
examples = """
14+
Example:
15+
./filemonitor -r # traces read of /var/log/syslog
16+
./filemonitor -f /path/to/config # traces filepaths in path for all events
17+
./filemonitor -f /path/to/config -d # traces filepaths in path for delete events
1518
"""
1619
parser = argparse.ArgumentParser(
1720
description="Monitors file actions",
1821
formatter_class=argparse.RawDescriptionHelpFormatter,
1922
epilog=examples)
20-
parser.add_argument("-f", "--file", default=sample_config, help="give config filepath")
23+
parser.add_argument("-f", "--file", default=sample_config, help="give config filepath")
24+
parser.add_argument("-r", "--read", action="store_true", help="trace read events")
25+
parser.add_argument("-w", "--write", action="store_true", help="trace write events")
26+
parser.add_argument("-p", "--rename", action="store_true", help="trace rename events")
27+
parser.add_argument("-c", "--create", action="store_true", help="trace create events")
28+
parser.add_argument("-d", "--delete", action="store_true", help="trace delete events")
29+
30+
def noflags(args):
31+
if(args.read or args.write or args.rename or args.create or args.delete):
32+
return False
33+
return True

filemonitor.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ struct data_t {
1515
BPF_HASH(inodemap, u32, u32);
1616
BPF_PERF_OUTPUT(events);
1717

18+
// common function takes dentry and operation name as arguments
19+
// looks up if inode exists in "inodemap" then trace and send event update
1820
static int common(struct pt_regs *ctx, struct dentry *de, char *OPRN) {
1921
if (de->d_name.len == 0) return 0;
2022

@@ -45,7 +47,8 @@ static int common(struct pt_regs *ctx, struct dentry *de, char *OPRN) {
4547
return 0;
4648
}
4749

48-
50+
// trace_read function takes file, buffer and size as arguments
51+
// this is attached to file read (vfs_read) events
4952
int trace_read(struct pt_regs *ctx, struct file *file,
5053
char __user *buf, size_t count)
5154
{
@@ -55,6 +58,8 @@ int trace_read(struct pt_regs *ctx, struct file *file,
5558
return common(ctx, file->f_path.dentry, OPRN);
5659
}
5760

61+
// trace_write function takes file, buffer and size as arguments
62+
// this is attached to file write (vfs_read) events
5863
int trace_write(struct pt_regs *ctx, struct file *file,
5964
char __user *buf, size_t count)
6065
{
@@ -64,6 +69,9 @@ int trace_write(struct pt_regs *ctx, struct file *file,
6469
return common(ctx, file->f_path.dentry, OPRN);
6570
}
6671

72+
// trace_rename function takes old directory inode,
73+
// old dentry, new directory inode, new dentry as arguments
74+
// this is attached to file rename (vfs_rename) events
6775
int trace_rename(struct pt_regs *ctx, struct inode *old_dir,
6876
struct dentry *old_dentry, struct inode *new_dir,
6977
struct dentry *new_dentry)
@@ -72,21 +80,27 @@ int trace_rename(struct pt_regs *ctx, struct inode *old_dir,
7280
return common(ctx, old_dentry, OPRN);
7381
}
7482

83+
// trace_write function takes old directory inode, dentry as arguments
84+
// this is attached to file create (security_inode_create) events
85+
// vfs_create is not fired by kernel > 4.8
7586
int trace_create(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
7687
{
7788
char OPRN[10] = "CREATE";
7889
return common(ctx, dentry, OPRN);
7990
};
8091

92+
// trace_write function takes old directory inode, dentry as arguments
93+
// this is attached to file unlinking(vfs_unlink) events to trace before deletion
8194
int trace_delete(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
8295
{
8396
char OPRN[10] = "DELETE";
8497
return common(ctx, dentry, OPRN);
8598
}
8699

87100
/*
88-
// KRETFUNC_PROBE function is triggered on process creation
101+
// KRETFUNC_PROBE probe is triggered on process creation
89102
// Linking it with file operation is hackish
103+
// TODO: Link with file events
90104
KRETFUNC_PROBE(__x64_sys_openat, struct pt_regs *regs, int ret)
91105
{
92106
struct data_t data = {};
@@ -101,4 +115,4 @@ KRETFUNC_PROBE(__x64_sys_openat, struct pt_regs *regs, int ret)
101115
events.perf_submit(ctx, &data, sizeof(data));
102116
return 0;
103117
}
104-
*/
118+
*/

filemonitor.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/python
22

33
from __future__ import print_function
4+
import json
45
from bcc import BPF
56
from ctypes import c_uint32
67

@@ -12,6 +13,7 @@
1213

1314
BPF_C_PROG = "filemonitor.c"
1415

16+
# initialize global variables
1517
def init():
1618
global BPF_C_PROG
1719
try:
@@ -20,6 +22,8 @@ def init():
2022
except:
2123
pass
2224

25+
# update_inodemap function takes BPFHASH inodemap, config file as arguments
26+
# reads config file, finds the inode and updates inodemap
2327
def update_inodemap(inodemap, config_file):
2428
if not config_file:
2529
raise FileNotFoundError
@@ -30,9 +34,12 @@ def update_inodemap(inodemap, config_file):
3034
inode_id = get_inode_from_filepath(filepath.strip())
3135
if inode_id != "":
3236
inodemap[c_uint32(int(inode_id))] = c_uint32(int(inode_id))
33-
37+
38+
# main function reads args and attaches bpf program
39+
# prints output of bpf events
3440
def main():
3541
args = cli.parser.parse_args()
42+
noflags = cli.noflags(args)
3643

3744
try:
3845
# initialize bpf program
@@ -43,11 +50,16 @@ def main():
4350
update_inodemap(b["inodemap"], args.file)
4451

4552
# attach probes
46-
b.attach_kprobe(event="vfs_read", fn_name="trace_read")
47-
b.attach_kprobe(event="vfs_write", fn_name="trace_write")
48-
b.attach_kprobe(event="vfs_rename", fn_name="trace_rename")
49-
b.attach_kprobe(event="security_inode_create", fn_name="trace_create")
50-
b.attach_kprobe(event="vfs_unlink", fn_name="trace_delete")
53+
if noflags or args.read:
54+
b.attach_kprobe(event="vfs_read", fn_name="trace_read")
55+
if noflags or args.write:
56+
b.attach_kprobe(event="vfs_write", fn_name="trace_write")
57+
if noflags or args.rename:
58+
b.attach_kprobe(event="vfs_rename", fn_name="trace_rename")
59+
if noflags or args.create:
60+
b.attach_kprobe(event="security_inode_create", fn_name="trace_create")
61+
if noflags or args.delete:
62+
b.attach_kprobe(event="vfs_unlink", fn_name="trace_delete")
5163

5264
# header
5365
print("%-6s %-4s %-4s %-32s %-32s %-32s %-4s" % ("PID", "UID", "CPU", "PROC", "FPATH", "COMM", "OPRN"))
@@ -70,7 +82,8 @@ def print_event(cpu, data, size):
7082
except Exception as e:
7183
print("Exception occured, Are you root? Is BPF installed?", e)
7284

73-
85+
# get_inode_from_filepath takes a filepath as argument
86+
# and returns inode associated with that file path
7487
def get_inode_from_filepath(filepath):
7588
cmd = f'ls {filepath} 2>&1 1>/dev/null && ls -i {filepath}'
7689
cmd += ' | awk \'{print $1}\''
@@ -81,6 +94,7 @@ def get_inode_from_filepath(filepath):
8194
except:
8295
return ""
8396

97+
# starts program
8498
if __name__ == "__main__":
8599
init()
86100
main()

0 commit comments

Comments
 (0)