pin link to a path and load from it
This commit is contained in:
parent
72ead3f149
commit
6989232973
@ -31,6 +31,7 @@ struct {
|
||||
__uint(max_entries, FILE_PROTECT_MAX);
|
||||
__type(key, file_protect_state);
|
||||
__type(value, __u64);
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} states SEC(".maps");
|
||||
|
||||
struct {
|
||||
@ -38,6 +39,7 @@ struct {
|
||||
__uint(max_entries, 256);
|
||||
__type(key, unsigned long);
|
||||
__type(value, __u8);
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} roots SEC(".maps");
|
||||
|
||||
struct {
|
||||
@ -45,6 +47,7 @@ struct {
|
||||
__uint(max_entries, 1024 * 1024);
|
||||
__type(key, unsigned long);
|
||||
__type(value, __u64);
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} banned_access SEC(".maps");
|
||||
|
||||
#define MAX_PATH_FRAGEMENTS 256
|
||||
@ -123,6 +126,8 @@ 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;
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
71
main.go
71
main.go
@ -34,6 +34,17 @@ const ( // bpf2go cannot restore enum to corresponding names. so i do it manuall
|
||||
FileProtectorFileProtectStateMax
|
||||
)
|
||||
|
||||
const (
|
||||
FileProtectorFilePathDisabled uint8 = iota
|
||||
FileProtectorFilePathEnabled
|
||||
)
|
||||
|
||||
const (
|
||||
// pin path
|
||||
PinPath = "/sys/fs/bpf/file_protector"
|
||||
LinkPinPath = PinPath + "/link_file_open"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fDebug := flag.Bool("debug", false, "toggle to show full ebpf verifier error")
|
||||
flag.Parse()
|
||||
@ -42,11 +53,20 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(PinPath, os.ModePerm); err != nil {
|
||||
log.Printf("W: failed to create ebpf pin path: %v. directory will not be protected if userspace daemon exited", err)
|
||||
} else {
|
||||
log.Printf("ebpf pin path is ensured to be a directory: %v", PinPath)
|
||||
}
|
||||
|
||||
fileProtectorObjects := FileProtectorObjects{}
|
||||
if err := LoadFileProtectorObjects(&fileProtectorObjects, &ebpf.CollectionOptions{
|
||||
Programs: ebpf.ProgramOptions{
|
||||
LogSize: ebpf.DefaultVerifierLogSize * 1024,
|
||||
},
|
||||
Maps: ebpf.MapOptions{
|
||||
PinPath: PinPath,
|
||||
},
|
||||
}); err != nil {
|
||||
var ve *ebpf.VerifierError
|
||||
if *fDebug && errors.As(err, &ve) {
|
||||
@ -59,16 +79,30 @@ func main() {
|
||||
defer fileProtectorObjects.Close()
|
||||
log.Println("lsm loaded")
|
||||
|
||||
lsm, err := link.AttachLSM(link.LSMOptions{
|
||||
Program: fileProtectorObjects.CheckFileOpen,
|
||||
})
|
||||
progLink, err := link.LoadPinnedLink(LinkPinPath, nil)
|
||||
if err != nil {
|
||||
log.Panic("failed to attach lsm: ", err)
|
||||
log.Printf("failed load pinned link(%s): %v. trying to attach the program", LinkPinPath, err)
|
||||
progLink, err = link.AttachLSM(link.LSMOptions{
|
||||
Program: fileProtectorObjects.CheckFileOpen,
|
||||
})
|
||||
if err != nil {
|
||||
log.Panic("failed to attach lsm: ", err)
|
||||
}
|
||||
log.Println("lsm attached")
|
||||
|
||||
if err := progLink.Pin(LinkPinPath); err != nil {
|
||||
log.Printf("W: failed to pin program: %v. ebpf will not survive after daemon exits.", err)
|
||||
} else {
|
||||
log.Printf("link pinned to %v", LinkPinPath)
|
||||
}
|
||||
log.Printf("to decrease refcount to release objects, simply run: sudo rm -r %v", PinPath)
|
||||
} else {
|
||||
log.Printf("lsm link loaded from existing pinned objects(%v)", LinkPinPath)
|
||||
}
|
||||
defer lsm.Close()
|
||||
log.Println("lsm attached")
|
||||
defer progLink.Close()
|
||||
|
||||
log.Println("configure maps...")
|
||||
newRoots := make(map[uint64]uint8)
|
||||
for _, path := range flag.Args() {
|
||||
path, _ = filepath.Abs(path)
|
||||
log.Println("-", path)
|
||||
@ -79,15 +113,30 @@ func main() {
|
||||
}
|
||||
switch stat := stat.Sys().(type) {
|
||||
case *syscall.Stat_t:
|
||||
if err := fileProtectorObjects.FileProtectorMaps.Roots.Update(stat.Ino, uint8(1), ebpf.UpdateAny); err != nil {
|
||||
if err := fileProtectorObjects.FileProtectorMaps.Roots.Update(stat.Ino, FileProtectorFilePathEnabled, ebpf.UpdateAny); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
newRoots[stat.Ino] = FileProtectorFilePathEnabled
|
||||
default:
|
||||
log.Printf("W: incompatible type of stat: %T", stat)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// you should also protect the daemon config itself
|
||||
|
||||
var (
|
||||
inoKey uint64
|
||||
inoEnabled uint8
|
||||
)
|
||||
iter := fileProtectorObjects.Roots.Iterate()
|
||||
for iter.Next(&inoKey, &inoEnabled) {
|
||||
if newRoots[inoKey] != FileProtectorFilePathEnabled && inoEnabled == FileProtectorFilePathEnabled {
|
||||
log.Printf("disabling root: %v", inoKey)
|
||||
if err := fileProtectorObjects.Roots.Update(inoKey, FileProtectorFilePathDisabled, 0); err != nil {
|
||||
log.Printf("W: failed to update root table when disable root: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: you should also protect the daemon config itself
|
||||
|
||||
log.Println("configuration done. enabling...")
|
||||
|
||||
@ -95,12 +144,14 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(time.Second * 10)
|
||||
ticker := time.NewTicker(time.Second * 5)
|
||||
defer ticker.Stop()
|
||||
log.Println("ticking...but with one step slower intentionally!")
|
||||
for {
|
||||
now := uint64(C.get_nsecs())
|
||||
log.Println("tick:", now)
|
||||
// TODO: read and show perf data
|
||||
|
||||
log.Printf("tick:%v", now)
|
||||
|
||||
if err := fileProtectorObjects.FileProtectorMaps.States.Update(FileProtectorFileProtectStateTick, uint64(now), ebpf.UpdateAny); err != nil {
|
||||
panic(err)
|
||||
|
Loading…
x
Reference in New Issue
Block a user