From a9f0f27ee2e6b6481b54e68e1c53a0926d9f0462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96zg=C3=BCr=20Kesim?= Date: Wed, 15 Jan 2020 19:04:56 +0100 Subject: [PATCH] Rough solution for Tasks 1, 2, 3 main.go: - reading /proc - iteration over entries in NNN/maps - filter glob-search for "*python3*" in pathname - find symbol and its offset in pathnanme - calculate offset in memory - add pid and offset to map TODO: encapsulating this into a module ebpf.go: - added type MapFD int, changing all function on a FD to methods This allows us to enrich the data type going forward - added bpf_update_elem() from the manpage ebpf2. .updateElement() is the verbatim wrapper to it. - added .Add/.Change/.Set methods, which call .updateElement with specific flags TODO: re-implement ebpf.go with pure go, using direct syscalls. --- GetRuntimeAddresses/ebpf/ebpf.go | 68 ++++++++++++++++++++++++++------ GetRuntimeAddresses/main.go | 6 +-- 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/GetRuntimeAddresses/ebpf/ebpf.go b/GetRuntimeAddresses/ebpf/ebpf.go index b513de7..241523a 100644 --- a/GetRuntimeAddresses/ebpf/ebpf.go +++ b/GetRuntimeAddresses/ebpf/ebpf.go @@ -20,8 +20,8 @@ static int bpf_create_map( { union bpf_attr attr = { .map_type = map_type, - .key_size = key_size, - .value_size = value_size, + .key_size = key_size, + .value_size = value_size, .max_entries = max_entries}; return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); @@ -31,8 +31,8 @@ int bpf_get_next_key(int fd, const void *key, void *next_key) { union bpf_attr attr = { .map_fd = fd, - .key = (__u64) (unsigned long) key, - .next_key = (__u64) (unsigned long) next_key}; + .key = (__u64) (unsigned long) key, + .next_key = (__u64) (unsigned long) next_key}; return bpf(BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr)); } @@ -41,15 +41,25 @@ int bpf_get_next_key(int fd, const void *key, void *next_key) int bpf_lookup_elem(int fd, const void *key, void *value) { union bpf_attr attr = { - .map_fd = fd, - .key = (__u64) (unsigned long) key, + .map_fd = fd, + .key = (__u64) (unsigned long) key, .value = (__u64) (unsigned long) value, }; return bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); } -// TODO: add insert +int bpf_update_elem(int fd, const void *key, const void *value, uint64_t flags) +{ + union bpf_attr attr = { + .map_fd = fd, + .key = (__u64) (unsigned long) key, + .value = (__u64) (unsigned long) value, + .flags = flags, + }; + + return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); +} */ import "C" @@ -59,18 +69,26 @@ import ( "unsafe" ) +type MapFD int + // CreateMap creates an eBPF map from int->uint64. The file descriptor of the // created map is returned. -func CreateMap() (int, error) { - mapFD := C.bpf_create_map(C.BPF_MAP_TYPE_HASH, 4, 8, 64) - return int(mapFD), nil +func CreateMap() (MapFD, error) { + + r, errno := C.bpf_create_map(C.BPF_MAP_TYPE_HASH, 4, 8, 64) + + if r == -1 { + return MapFD(r), fmt.Errorf("bpf_create_map with errno %d", errno) + } + + return MapFD(r), nil } // GetMap gets the key/value pairs from the specified eBPF map as a Go map -func GetMap(mapFD int) (map[int]uint64, error) { +func (mfd MapFD) GetMap() (map[int]uint64, error) { retMap := make(map[int]uint64) - mapFDC := C.int(mapFD) + mapFDC := C.int(mfd) keyC := C.int(0) nextKeyC := C.int(0) valC := C.uint64_t(0) @@ -94,3 +112,29 @@ func GetMap(mapFD int) (map[int]uint64, error) { keyC = nextKeyC } } + +func (mfd MapFD) Add(key int, value uint64) error { + return mfd.updateElement(key, value, C.BPF_NOEXIST) +} + +func (mfd MapFD) Change(key int, value uint64) error { + return mfd.updateElement(key, value, C.BPF_EXIST) +} + +func (mfd MapFD) Set(key int, value uint64) error { + return mfd.updateElement(key, value, C.BPF_ANY) +} + +func (mfd MapFD) updateElement(key int, value uint64, flag C.uint64_t) error { + + r, errno := C.bpf_update_elem(C.int(mfd), + unsafe.Pointer(&key), + unsafe.Pointer(&value), + flag) + + if r == -1 { + return fmt.Errorf("bpf_update_elem failed with errno %d", errno) + } + + return nil +} diff --git a/GetRuntimeAddresses/main.go b/GetRuntimeAddresses/main.go index ecd0d43..90c75a0 100644 --- a/GetRuntimeAddresses/main.go +++ b/GetRuntimeAddresses/main.go @@ -56,11 +56,11 @@ func main() { } else if offset, found := searchSymbolIn(pid_s, "*python3*", "_PyRuntime"); !found { continue } else { - fmt.Printf("going to set (%d -> 0x%x)\n\n", pid, offset) + mapFD.Add(pid, uint64(offset)) } } - mapContents, err := ebpf.GetMap(mapFD) + mapContents, err := mapFD.GetMap() if err != nil { fmt.Printf("Failed to get the map contents: %s", err) os.Exit(1) @@ -161,7 +161,7 @@ func searchSymbolIn(pid, glob, symbol string) (offset uint64, ok bool) { memoff := sym.Value - section.Addr + alignedOffset(section) - fmt.Printf("pid: %s\nsym: %#v\nsection: %#v\nmemoff: 0x%x\narange: %#v\nmap-fileoffset: 0x%x\npathname: %s\n", pid, sym, section, memoff, arange, fileoffset, pathname) + // fmt.Printf("pid: %s\nsym: %#v\nsection: %#v\nmemoff: 0x%x\narange: %#v\nmap-fileoffset: 0x%x\npathname: %s\n", pid, sym, section, memoff, arange, fileoffset, pathname) // stop when only _one_ is found return arange.start + memoff - fileoffset, true