Add vmlinux.h and implement get_goid_from_thread_local_storage

This commit is contained in:
M. Mert Yildiran
2022-06-28 15:04:21 +03:00
parent 5fbd2bbe06
commit ff003542e5
8 changed files with 124136 additions and 28 deletions
+64 -4
View File
@@ -64,6 +64,46 @@ enum ABI {
ABIInternal=1,
};
static __always_inline int get_goid_from_thread_local_storage(__u64 *goroutine_id) {
int zero = 0;
int one = 1;
__u32* g_addr_offset = bpf_map_lookup_elem(&goid_offset_map, &zero);
__u32* goid_offset = bpf_map_lookup_elem(&goid_offset_map, &one);
if (g_addr_offset == NULL || goid_offset == NULL) {
return 0;
}
// Since eBPF programs have such strict stack requirements
// me must implement our own heap using a ringbuffer.
// Reserve some memory in our "heap" for the task_struct.
struct task_struct *task;
task = bpf_ringbuf_reserve(&heap, sizeof(struct task_struct), 0);
if (!task) {
return 0;
}
// Get the current task.
__u64 task_ptr = bpf_get_current_task();
if (!task_ptr) {
bpf_ringbuf_discard(task, 0);
return 0;
}
// The bpf_get_current_task helper returns us the address of the task_struct in
// kernel memory. Use the bpf_probe_read_kernel helper to read the struct out of
// kernel memory.
bpf_probe_read_kernel(task, sizeof(struct task_struct), (void*)(task_ptr));
// Get the Goroutine ID which is stored in thread local storage.
size_t g_addr;
bpf_probe_read_user(&g_addr, sizeof(void *), (void*)(task->thread.fsbase + g_addr_offset));
bpf_probe_read_user(goroutine_id, sizeof(void *), (void*)(g_addr + goid_offset));
// Free back up the memory we reserved for the task_struct.
bpf_ringbuf_discard(task, 0);
return 1;
}
static __always_inline __u32 go_crypto_tls_get_fd_from_tcp_conn(struct pt_regs *ctx) {
struct go_interface conn;
long err;
@@ -119,8 +159,18 @@ static __always_inline void go_crypto_tls_uprobe(struct pt_regs *ctx, struct bpf
info.buffer = (void*)GO_ABI_INTERNAL_PT_REGS_R4(ctx);
info.fd = go_crypto_tls_get_fd_from_tcp_conn(ctx);
// GO_ABI_INTERNAL_PT_REGS_GP is Goroutine address
__u64 pid_fp = pid << 32 | GO_ABI_INTERNAL_PT_REGS_GP(ctx);
__u64 goroutine_id;
if (abi == ABI0) {
// In case of ABI0 and amd64, it's stored in the thread-local storage
int status = get_goid_from_thread_local_storage(&goroutine_id);
if (!status) {
return;
}
} else {
// GO_ABI_INTERNAL_PT_REGS_GP is Goroutine address
goroutine_id = GO_ABI_INTERNAL_PT_REGS_GP(ctx);
}
__u64 pid_fp = pid << 32 | goroutine_id;
err = bpf_map_update_elem(go_context, &pid_fp, &info, BPF_ANY);
if (err != 0) {
@@ -137,8 +187,18 @@ static __always_inline void go_crypto_tls_ex_uprobe(struct pt_regs *ctx, struct
return;
}
// GO_ABI_INTERNAL_PT_REGS_GP is Goroutine address
__u64 pid_fp = pid << 32 | GO_ABI_INTERNAL_PT_REGS_GP(ctx);
__u64 goroutine_id;
if (abi == ABI0) {
// In case of ABI0 and amd64, it's stored in the thread-local storage
int status = get_goid_from_thread_local_storage(&goroutine_id);
if (!status) {
return;
}
} else {
// GO_ABI_INTERNAL_PT_REGS_GP is Goroutine address
goroutine_id = GO_ABI_INTERNAL_PT_REGS_GP(ctx);
}
__u64 pid_fp = pid << 32 | goroutine_id;
struct ssl_info *info_ptr = bpf_map_lookup_elem(go_context, &pid_fp);
if (info_ptr == NULL) {
+9 -9
View File
@@ -78,15 +78,15 @@ https://github.com/golang/go/blob/go1.17.6/src/cmd/compile/internal/ssa/gen/AMD6
#else
#define GO_ABI_INTERNAL_PT_REGS_R1(x) ((x)->rax)
#define GO_ABI_INTERNAL_PT_REGS_R2(x) ((x)->rcx)
#define GO_ABI_INTERNAL_PT_REGS_R3(x) ((x)->rdx)
#define GO_ABI_INTERNAL_PT_REGS_R4(x) ((x)->rbx)
#define GO_ABI_INTERNAL_PT_REGS_R5(x) ((x)->rbp)
#define GO_ABI_INTERNAL_PT_REGS_R6(x) ((x)->rsi)
#define GO_ABI_INTERNAL_PT_REGS_R7(x) ((x)->rdi)
#define GO_ABI_INTERNAL_PT_REGS_SP(x) ((x)->rsp)
#define GO_ABI_INTERNAL_PT_REGS_FP(x) ((x)->rbp)
#define GO_ABI_INTERNAL_PT_REGS_R1(x) ((x)->ax)
#define GO_ABI_INTERNAL_PT_REGS_R2(x) ((x)->cx)
#define GO_ABI_INTERNAL_PT_REGS_R3(x) ((x)->dx)
#define GO_ABI_INTERNAL_PT_REGS_R4(x) ((x)->bx)
#define GO_ABI_INTERNAL_PT_REGS_R5(x) ((x)->bp)
#define GO_ABI_INTERNAL_PT_REGS_R6(x) ((x)->si)
#define GO_ABI_INTERNAL_PT_REGS_R7(x) ((x)->di)
#define GO_ABI_INTERNAL_PT_REGS_SP(x) ((x)->sp)
#define GO_ABI_INTERNAL_PT_REGS_FP(x) ((x)->bp)
#define GO_ABI_INTERNAL_PT_REGS_GP(x) ((x)->r14)
#endif
+1 -3
View File
@@ -7,9 +7,7 @@ Copyright (C) UP9 Inc.
#ifndef __HEADERS__
#define __HEADERS__
#include <stddef.h>
#include <linux/bpf.h>
#include <linux/ptrace.h>
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include "bpf/bpf_tracing.h"
+1 -1
View File
@@ -91,7 +91,7 @@ BPF_LRU_HASH(openssl_write_context, __u64, struct ssl_info);
BPF_LRU_HASH(openssl_read_context, __u64, struct ssl_info);
// Go specific
BPF_HASH(goid_offset, __u32, __u32);
BPF_HASH(goid_offset_map, __u32, __u32);
BPF_LRU_HASH(go_write_context, __u64, struct ssl_info);
BPF_LRU_HASH(go_read_context, __u64, struct ssl_info);
File diff suppressed because it is too large Load Diff
+6 -3
View File
@@ -87,9 +87,12 @@ func (s *goHooks) installHooks(bpfObjects *tlsTapperObjects, ex *link.Executable
s.goReadExProbes = append(s.goReadExProbes, probe)
}
// Pass goid offset to an eBPF map to retrieve it in eBPF context
goidOffsetMap := bpfObjects.tlsTapperMaps.GoidOffset
if err := goidOffsetMap.Put(0, offsets.GoidOffset); err != nil {
// Pass goid and g struct offsets to an eBPF map to retrieve it in eBPF context
goidOffsetMap := bpfObjects.tlsTapperMaps.GoidOffsetMap
if err := goidOffsetMap.Put(0, offsets.GStructOffset); err != nil {
return errors.Wrap(err, 0)
}
if err := goidOffsetMap.Put(1, offsets.GoidOffset); err != nil {
return errors.Wrap(err, 0)
}
+8 -5
View File
@@ -28,6 +28,7 @@ type goOffsets struct {
GoVersion string
Abi goAbi
GoidOffset dwarf.Offset
GStructOffset dwarf.Offset
}
type goExtendedOffset struct {
@@ -43,7 +44,7 @@ const (
)
func findGoOffsets(filePath string) (goOffsets, error) {
offsets, goidOffset, err := getOffsets(filePath)
offsets, goidOffset, gStructOffset, err := getOffsets(filePath)
if err != nil {
return goOffsets{}, err
}
@@ -80,10 +81,11 @@ func findGoOffsets(filePath string) (goOffsets, error) {
GoVersion: goVersion,
Abi: abi,
GoidOffset: goidOffset,
GStructOffset: gStructOffset,
}, nil
}
func getGoidOffset(elfFile *elf.File) (offset dwarf.Offset, err error) {
func getGoidOffset(elfFile *elf.File) (goidOffset dwarf.Offset, gStructOffset dwarf.Offset, err error) {
var dwarfData *dwarf.Data
dwarfData, err = elfFile.DWARF()
if err != nil {
@@ -110,6 +112,7 @@ func getGoidOffset(elfFile *elf.File) (offset dwarf.Offset, err error) {
if field.Attr == dwarf.AttrName {
val := field.Val.(string)
if val == "runtime.g" {
gStructOffset = entry.Offset
seenRuntimeG = true
}
}
@@ -123,7 +126,7 @@ func getGoidOffset(elfFile *elf.File) (offset dwarf.Offset, err error) {
if field.Attr == dwarf.AttrName {
val := field.Val.(string)
if val == "goid" {
offset = entry.Offset
goidOffset = entry.Offset
return
}
}
@@ -135,7 +138,7 @@ func getGoidOffset(elfFile *elf.File) (offset dwarf.Offset, err error) {
return
}
func getOffsets(filePath string) (offsets map[string]*goExtendedOffset, goidOffset dwarf.Offset, err error) {
func getOffsets(filePath string) (offsets map[string]*goExtendedOffset, goidOffset dwarf.Offset, gStructOffset dwarf.Offset, err error) {
var engine gapstone.Engine
switch runtime.GOARCH {
case "amd64":
@@ -258,7 +261,7 @@ func getOffsets(filePath string) (offsets map[string]*goExtendedOffset, goidOffs
offsets[sym.Name] = extendedOffset
}
goidOffset, err = getGoidOffset(elfFile)
goidOffset, gStructOffset, err = getGoidOffset(elfFile)
return
}
+3 -3
View File
@@ -100,7 +100,7 @@ type tlsTapperMapSpecs struct {
FileDescriptorToIpv4 *ebpf.MapSpec `ebpf:"file_descriptor_to_ipv4"`
GoReadContext *ebpf.MapSpec `ebpf:"go_read_context"`
GoWriteContext *ebpf.MapSpec `ebpf:"go_write_context"`
GoidOffset *ebpf.MapSpec `ebpf:"goid_offset"`
GoidOffsetMap *ebpf.MapSpec `ebpf:"goid_offset_map"`
Heap *ebpf.MapSpec `ebpf:"heap"`
LogBuffer *ebpf.MapSpec `ebpf:"log_buffer"`
OpensslReadContext *ebpf.MapSpec `ebpf:"openssl_read_context"`
@@ -133,7 +133,7 @@ type tlsTapperMaps struct {
FileDescriptorToIpv4 *ebpf.Map `ebpf:"file_descriptor_to_ipv4"`
GoReadContext *ebpf.Map `ebpf:"go_read_context"`
GoWriteContext *ebpf.Map `ebpf:"go_write_context"`
GoidOffset *ebpf.Map `ebpf:"goid_offset"`
GoidOffsetMap *ebpf.Map `ebpf:"goid_offset_map"`
Heap *ebpf.Map `ebpf:"heap"`
LogBuffer *ebpf.Map `ebpf:"log_buffer"`
OpensslReadContext *ebpf.Map `ebpf:"openssl_read_context"`
@@ -149,7 +149,7 @@ func (m *tlsTapperMaps) Close() error {
m.FileDescriptorToIpv4,
m.GoReadContext,
m.GoWriteContext,
m.GoidOffset,
m.GoidOffsetMap,
m.Heap,
m.LogBuffer,
m.OpensslReadContext,