diff --git a/bpf/lsm.c b/bpf/lsm.c index 040ddc6..ee49e66 100644 --- a/bpf/lsm.c +++ b/bpf/lsm.c @@ -24,6 +24,7 @@ typedef struct check_ctx { struct dentry *dentry; __u64 need_to_be_checked; __u64 return_value; + __u64 root_inode; } check_ctx; struct { @@ -65,6 +66,7 @@ static __u64 check_file_need_protection(struct bpf_map *map, // enumerate from the leaf to root while (count_down-- > 0 && dentry != NULL) { if (dentry->d_inode->i_ino == *inode) { + ctx->root_inode = dentry->d_inode->i_ino; ctx->need_to_be_checked = 1; return 1; } @@ -111,6 +113,9 @@ int BPF_PROG(check_file_open, struct file *file, int ret) { if (ret != 0) return ret; + __u64 counter_init_val = 1; + __u64 *counter; + check_ctx data = { .dentry = file->f_path.dentry, .need_to_be_checked = 0, @@ -126,10 +131,18 @@ int BPF_PROG(check_file_open, struct file *file, int ret) { data.need_to_be_checked = 1; bpf_for_each_map_elem(&states, check_service_status, &data, 0); - // TODO: write perf data - if (!data.need_to_be_checked) { return 0; } + + if (data.return_value != 0) { + counter = bpf_map_lookup_elem(&banned_access, &data.root_inode); + if (counter == NULL) + bpf_map_update_elem(&banned_access, &data.root_inode, &counter_init_val, + BPF_ANY); + else + __sync_fetch_and_add(counter, 1); + } + return data.return_value; } diff --git a/fileprotector_bpfeb.o b/fileprotector_bpfeb.o index 5a46db8..5c52f83 100644 Binary files a/fileprotector_bpfeb.o and b/fileprotector_bpfeb.o differ diff --git a/fileprotector_bpfel.o b/fileprotector_bpfel.o index f6533eb..e8e0a36 100644 Binary files a/fileprotector_bpfel.o and b/fileprotector_bpfel.o differ diff --git a/main.go b/main.go index 5e08d3d..158abe5 100644 --- a/main.go +++ b/main.go @@ -102,7 +102,7 @@ func main() { defer progLink.Close() log.Println("configure maps...") - newRoots := make(map[uint64]uint8) + newRoots := make(map[uint64]string) for _, path := range flag.Args() { path, _ = filepath.Abs(path) log.Println("-", path) @@ -116,7 +116,7 @@ func main() { if err := fileProtectorObjects.FileProtectorMaps.Roots.Update(stat.Ino, FileProtectorFilePathEnabled, ebpf.UpdateAny); err != nil { panic(err) } - newRoots[stat.Ino] = FileProtectorFilePathEnabled + newRoots[stat.Ino] = path default: log.Printf("W: incompatible type of stat: %T", stat) continue @@ -129,8 +129,8 @@ func main() { ) iter := fileProtectorObjects.Roots.Iterate() for iter.Next(&inoKey, &inoEnabled) { - if newRoots[inoKey] != FileProtectorFilePathEnabled && inoEnabled == FileProtectorFilePathEnabled { - log.Printf("disabling root: %v", inoKey) + if path, ok := newRoots[inoKey]; ok && inoEnabled == FileProtectorFilePathEnabled { + log.Printf("disabling root: %v(%v)", path, inoKey) if err := fileProtectorObjects.Roots.Update(inoKey, FileProtectorFilePathDisabled, 0); err != nil { log.Printf("W: failed to update root table when disable root: %v", err) } @@ -147,11 +147,33 @@ func main() { ticker := time.NewTicker(time.Second * 5) defer ticker.Stop() log.Println("ticking...but with one step slower intentionally!") + prevBannedAccesses := make(map[uint64]uint64) for { now := uint64(C.get_nsecs()) // TODO: read and show perf data - log.Printf("tick:%v", now) + perf := "" + bannedAccesses := fileProtectorObjects.BannedAccess.Iterate() + var ( + bannedRoot, counter uint64 + ) + for bannedAccesses.Next(&bannedRoot, &counter) { + name := fmt.Sprintf("inode(%v)", bannedRoot) + + if path, ok := newRoots[bannedRoot]; ok { + name = path + } + if prevCounter, ok := prevBannedAccesses[bannedRoot]; ok { + if counter-prevCounter > 0 { + perf += fmt.Sprintf(" %v=+%v", name, counter-prevCounter) + } + } else { + perf += fmt.Sprintf(" %v=%v", name, counter) + } + prevBannedAccesses[bannedRoot] = counter + } + + log.Printf("tick:%v%v", now, perf) if err := fileProtectorObjects.FileProtectorMaps.States.Update(FileProtectorFileProtectStateTick, uint64(now), ebpf.UpdateAny); err != nil { panic(err)