mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-06-26 16:24:54 +00:00
Add golang_uprobes.c
This commit is contained in:
parent
e8653f8cdf
commit
464aa98f23
156
tap/tlstapper/bpf/golang_uprobes.c
Normal file
156
tap/tlstapper/bpf/golang_uprobes.c
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
Note: This file is licenced differently from the rest of the project
|
||||
SPDX-License-Identifier: GPL-2.0
|
||||
Copyright (C) UP9 Inc.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "include/headers.h"
|
||||
#include "include/maps.h"
|
||||
|
||||
#define MAX_ENTRIES_LRU_HASH (1 << 14) // 16384
|
||||
#define MAX_ENTRIES_RINGBUFF (1 << 24) // 16777216
|
||||
#define BUFFER_SIZE_READ_WRITE (1 << 19) // 512 KiB
|
||||
|
||||
|
||||
struct socket {
|
||||
__u32 pid;
|
||||
__u32 fd;
|
||||
__u32 key_dial;
|
||||
};
|
||||
|
||||
struct golang_read_write {
|
||||
__u32 pid;
|
||||
__u32 fd;
|
||||
__u32 conn_addr;
|
||||
bool is_request;
|
||||
__u32 len;
|
||||
__u32 cap;
|
||||
__u8 data[BUFFER_SIZE_READ_WRITE];
|
||||
};
|
||||
|
||||
BPF_LRU_HASH(golang_socket_dials, __u64, struct socket);
|
||||
BPF_LRU_HASH(golang_dial_writes, __u32, struct socket);
|
||||
BPF_RINGBUF(golang_read_writes);
|
||||
|
||||
const struct golang_read_write *unused __attribute__((unused));
|
||||
|
||||
|
||||
SEC("uprobe/golang_crypto_tls_write")
|
||||
static __always_inline int golang_crypto_tls_write_uprobe(struct pt_regs *ctx) {
|
||||
void* stack_addr = (void*)ctx->rsp;
|
||||
__u32 key_dial;
|
||||
// Address at ctx->rsp + 0x20 is common between golang_crypto_tls_write_uprobe and golang_net_http_dialconn_uprobe
|
||||
__u32 status = bpf_probe_read(&key_dial, sizeof(key_dial), stack_addr + 0x20);
|
||||
if (status < 0) {
|
||||
bpf_printk("[golang_crypto_tls_write_uprobe] error reading key_dial: %d", status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct socket *s = bpf_map_lookup_elem(&golang_dial_writes, &key_dial);
|
||||
if (s == NULL) {
|
||||
bpf_printk("[golang_crypto_tls_write_uprobe] error getting socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct golang_read_write *b = NULL;
|
||||
b = bpf_ringbuf_reserve(&golang_read_writes, sizeof(struct golang_read_write), 0);
|
||||
if (!b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
b->pid = pid_tgid >> 32;
|
||||
b->fd = s->fd;
|
||||
// ctx->rsi is common between golang_crypto_tls_write_uprobe and golang_net_http_read_uprobe
|
||||
b->conn_addr = ctx->rsi; // go.itab.*net.TCPConn,net.Conn address
|
||||
b->is_request = true;
|
||||
b->len = ctx->rcx;
|
||||
b->cap = ctx->rdi;
|
||||
|
||||
status = bpf_probe_read_str(&b->data, sizeof(b->data), (void*)ctx->rbx);
|
||||
if (status < 0) {
|
||||
bpf_printk("[golang_crypto_tls_write_uprobe] error reading data: %d", status);
|
||||
bpf_ringbuf_discard(b, BPF_RB_FORCE_WAKEUP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bpf_ringbuf_submit(b, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uprobe/golang_net_http_read")
|
||||
static __always_inline int golang_net_http_read_uprobe(struct pt_regs *ctx) {
|
||||
struct golang_read_write *b = NULL;
|
||||
b = bpf_ringbuf_reserve(&golang_read_writes, sizeof(struct golang_read_write), 0);
|
||||
if (!b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
b->pid = pid_tgid >> 32;
|
||||
// ctx->rsi is common between golang_crypto_tls_write_uprobe and golang_net_http_read_uprobe
|
||||
b->conn_addr = ctx->rsi; // go.itab.*net.TCPConn,net.Conn address
|
||||
b->is_request = false;
|
||||
b->len = ctx->rax;
|
||||
b->cap = ctx->r10;
|
||||
|
||||
__u32 status = bpf_probe_read_str(&b->data, sizeof(b->data), (void*)ctx->r8);
|
||||
if (status < 0) {
|
||||
bpf_printk("[golang_net_http_read_uprobe] error reading data: %d", status);
|
||||
bpf_ringbuf_discard(b, BPF_RB_FORCE_WAKEUP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bpf_ringbuf_submit(b, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uprobe/golang_net_socket")
|
||||
static __always_inline int golang_net_socket_uprobe(struct pt_regs *ctx) {
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
__u64 pid = pid_tgid >> 32;
|
||||
// ctx->r14 is common between golang_net_socket_uprobe and golang_net_http_dialconn_uprobe
|
||||
__u64 key_socket = (pid << 32) + ctx->r14;
|
||||
struct socket *s = bpf_map_lookup_elem(&golang_socket_dials, &key_socket);
|
||||
if (s == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct socket b = { .pid = s->pid, .fd = ctx->rax, .key_dial = s->key_dial };
|
||||
|
||||
__u32 status = bpf_map_update_elem(&golang_dial_writes, &s->key_dial, &b, BPF_ANY);
|
||||
if (status != 0) {
|
||||
bpf_printk("[golang_net_socket_uprobe] error updating socket file descriptor: %d", status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uprobe/golang_net_http_dialconn")
|
||||
static __always_inline int golang_net_http_dialconn_uprobe(struct pt_regs *ctx) {
|
||||
void* stack_addr = (void*)ctx->rsp;
|
||||
__u32 key_dial;
|
||||
// Address at ctx->rsp + 0x250 is common between golang_crypto_tls_write_uprobe and golang_net_http_dialconn_uprobe
|
||||
__u32 status = bpf_probe_read(&key_dial, sizeof(key_dial), stack_addr + 0x250);
|
||||
if (status < 0) {
|
||||
bpf_printk("[golang_net_http_dialconn_uprobe] error reading key_dial: %d", status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
struct socket b = { .pid = pid_tgid >> 32, .fd = 0, .key_dial = key_dial };
|
||||
|
||||
__u64 pid = b.pid;
|
||||
// ctx->r14 is common between golang_net_socket_uprobe and golang_net_http_dialconn_uprobe
|
||||
__u64 key_socket = (pid << 32) + ctx->r14;
|
||||
status = bpf_map_update_elem(&golang_socket_dials, &key_socket, &b, BPF_ANY);
|
||||
if (status != 0) {
|
||||
bpf_printk("[golang_net_socket_uprobe] error setting socket: %d", status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -16,6 +16,11 @@ Copyright (C) UP9 Inc.
|
||||
// One minute in nano seconds. Chosen by gut feeling.
|
||||
#define SSL_INFO_MAX_TTL_NANO (1000000000l * 60l)
|
||||
|
||||
#define MAX_ENTRIES_HASH (1 << 12) // 4096
|
||||
#define MAX_ENTRIES_PERF_OUTPUT (1 << 10) // 1024
|
||||
#define MAX_ENTRIES_LRU_HASH (1 << 14) // 16384
|
||||
#define MAX_ENTRIES_RINGBUFF (1 << 24) // 16777216
|
||||
|
||||
// The same struct can be found in chunk.go
|
||||
//
|
||||
// Be careful when editing, alignment and padding should be exactly the same in go/c.
|
||||
@ -57,13 +62,19 @@ struct fd_info {
|
||||
};
|
||||
|
||||
#define BPF_HASH(_name, _key_type, _value_type) \
|
||||
BPF_MAP(_name, BPF_MAP_TYPE_HASH, _key_type, _value_type, 4096)
|
||||
BPF_MAP(_name, BPF_MAP_TYPE_HASH, _key_type, _value_type, MAX_ENTRIES_HASH)
|
||||
|
||||
#define BPF_PERF_OUTPUT(_name) \
|
||||
BPF_MAP(_name, BPF_MAP_TYPE_PERF_EVENT_ARRAY, int, __u32, 1024)
|
||||
BPF_MAP(_name, BPF_MAP_TYPE_PERF_EVENT_ARRAY, int, __u32, MAX_ENTRIES_PERF_OUTPUT)
|
||||
|
||||
#define BPF_LRU_HASH(_name, _key_type, _value_type) \
|
||||
BPF_MAP(_name, BPF_MAP_TYPE_LRU_HASH, _key_type, _value_type, 16384)
|
||||
BPF_MAP(_name, BPF_MAP_TYPE_LRU_HASH, _key_type, _value_type, MAX_ENTRIES_LRU_HASH)
|
||||
|
||||
#define BPF_RINGBUF(_name) \
|
||||
struct { \
|
||||
__uint(type, BPF_MAP_TYPE_RINGBUF); \
|
||||
__uint(max_entries, MAX_ENTRIES_RINGBUFF); \
|
||||
} _name SEC(".maps"); \
|
||||
|
||||
BPF_HASH(pids_map, __u32, __u32);
|
||||
BPF_LRU_HASH(ssl_write_context, __u64, struct ssl_info);
|
||||
|
@ -14,6 +14,7 @@ Copyright (C) UP9 Inc.
|
||||
// To avoid multiple .o files
|
||||
//
|
||||
#include "openssl_uprobes.c"
|
||||
#include "golang_uprobes.c"
|
||||
#include "fd_tracepoints.c"
|
||||
#include "fd_to_address_tracepoints.c"
|
||||
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
const GLOABL_TAP_PID = 0
|
||||
|
||||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go tlsTapper bpf/tls_tapper.c -- -O2 -g -D__TARGET_ARCH_x86
|
||||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go@0d0727ef53e2f53b1731c73f4c61e0f58693083a -type golang_read_write tlsTapper bpf/tls_tapper.c -- -O2 -g -D__TARGET_ARCH_x86
|
||||
|
||||
type TlsTapper struct {
|
||||
bpfObjects tlsTapperObjects
|
||||
|
@ -13,6 +13,29 @@ import (
|
||||
"github.com/cilium/ebpf"
|
||||
)
|
||||
|
||||
type tlsTapperGolangReadWrite struct {
|
||||
Pid uint32
|
||||
Fd uint32
|
||||
ConnAddr uint32
|
||||
IsRequest bool
|
||||
_ [3]byte
|
||||
Len uint32
|
||||
Cap uint32
|
||||
Data [524288]uint8
|
||||
}
|
||||
|
||||
type tlsTapperTlsChunk struct {
|
||||
Pid uint32
|
||||
Tgid uint32
|
||||
Len uint32
|
||||
Start uint32
|
||||
Recorded uint32
|
||||
Fd uint32
|
||||
Flags uint32
|
||||
Address [16]uint8
|
||||
Data [4096]uint8
|
||||
}
|
||||
|
||||
// loadTlsTapper returns the embedded CollectionSpec for tlsTapper.
|
||||
func loadTlsTapper() (*ebpf.CollectionSpec, error) {
|
||||
reader := bytes.NewReader(_TlsTapperBytes)
|
||||
@ -54,6 +77,10 @@ type tlsTapperSpecs struct {
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapperProgramSpecs struct {
|
||||
GolangCryptoTlsWriteUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_write_uprobe"`
|
||||
GolangNetHttpDialconnUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_dialconn_uprobe"`
|
||||
GolangNetHttpReadUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_read_uprobe"`
|
||||
GolangNetSocketUprobe *ebpf.ProgramSpec `ebpf:"golang_net_socket_uprobe"`
|
||||
SslRead *ebpf.ProgramSpec `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.ProgramSpec `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.ProgramSpec `ebpf:"ssl_ret_read"`
|
||||
@ -78,6 +105,9 @@ type tlsTapperMapSpecs struct {
|
||||
ChunksBuffer *ebpf.MapSpec `ebpf:"chunks_buffer"`
|
||||
ConnectSyscallInfo *ebpf.MapSpec `ebpf:"connect_syscall_info"`
|
||||
FileDescriptorToIpv4 *ebpf.MapSpec `ebpf:"file_descriptor_to_ipv4"`
|
||||
GolangDialWrites *ebpf.MapSpec `ebpf:"golang_dial_writes"`
|
||||
GolangReadWrites *ebpf.MapSpec `ebpf:"golang_read_writes"`
|
||||
GolangSocketDials *ebpf.MapSpec `ebpf:"golang_socket_dials"`
|
||||
Heap *ebpf.MapSpec `ebpf:"heap"`
|
||||
LogBuffer *ebpf.MapSpec `ebpf:"log_buffer"`
|
||||
PidsMap *ebpf.MapSpec `ebpf:"pids_map"`
|
||||
@ -108,6 +138,9 @@ type tlsTapperMaps struct {
|
||||
ChunksBuffer *ebpf.Map `ebpf:"chunks_buffer"`
|
||||
ConnectSyscallInfo *ebpf.Map `ebpf:"connect_syscall_info"`
|
||||
FileDescriptorToIpv4 *ebpf.Map `ebpf:"file_descriptor_to_ipv4"`
|
||||
GolangDialWrites *ebpf.Map `ebpf:"golang_dial_writes"`
|
||||
GolangReadWrites *ebpf.Map `ebpf:"golang_read_writes"`
|
||||
GolangSocketDials *ebpf.Map `ebpf:"golang_socket_dials"`
|
||||
Heap *ebpf.Map `ebpf:"heap"`
|
||||
LogBuffer *ebpf.Map `ebpf:"log_buffer"`
|
||||
PidsMap *ebpf.Map `ebpf:"pids_map"`
|
||||
@ -121,6 +154,9 @@ func (m *tlsTapperMaps) Close() error {
|
||||
m.ChunksBuffer,
|
||||
m.ConnectSyscallInfo,
|
||||
m.FileDescriptorToIpv4,
|
||||
m.GolangDialWrites,
|
||||
m.GolangReadWrites,
|
||||
m.GolangSocketDials,
|
||||
m.Heap,
|
||||
m.LogBuffer,
|
||||
m.PidsMap,
|
||||
@ -133,6 +169,10 @@ func (m *tlsTapperMaps) Close() error {
|
||||
//
|
||||
// It can be passed to loadTlsTapperObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapperPrograms struct {
|
||||
GolangCryptoTlsWriteUprobe *ebpf.Program `ebpf:"golang_crypto_tls_write_uprobe"`
|
||||
GolangNetHttpDialconnUprobe *ebpf.Program `ebpf:"golang_net_http_dialconn_uprobe"`
|
||||
GolangNetHttpReadUprobe *ebpf.Program `ebpf:"golang_net_http_read_uprobe"`
|
||||
GolangNetSocketUprobe *ebpf.Program `ebpf:"golang_net_socket_uprobe"`
|
||||
SslRead *ebpf.Program `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.Program `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.Program `ebpf:"ssl_ret_read"`
|
||||
@ -151,6 +191,10 @@ type tlsTapperPrograms struct {
|
||||
|
||||
func (p *tlsTapperPrograms) Close() error {
|
||||
return _TlsTapperClose(
|
||||
p.GolangCryptoTlsWriteUprobe,
|
||||
p.GolangNetHttpDialconnUprobe,
|
||||
p.GolangNetHttpReadUprobe,
|
||||
p.GolangNetSocketUprobe,
|
||||
p.SslRead,
|
||||
p.SslReadEx,
|
||||
p.SslRetRead,
|
||||
|
Binary file not shown.
@ -13,6 +13,29 @@ import (
|
||||
"github.com/cilium/ebpf"
|
||||
)
|
||||
|
||||
type tlsTapperGolangReadWrite struct {
|
||||
Pid uint32
|
||||
Fd uint32
|
||||
ConnAddr uint32
|
||||
IsRequest bool
|
||||
_ [3]byte
|
||||
Len uint32
|
||||
Cap uint32
|
||||
Data [524288]uint8
|
||||
}
|
||||
|
||||
type tlsTapperTlsChunk struct {
|
||||
Pid uint32
|
||||
Tgid uint32
|
||||
Len uint32
|
||||
Start uint32
|
||||
Recorded uint32
|
||||
Fd uint32
|
||||
Flags uint32
|
||||
Address [16]uint8
|
||||
Data [4096]uint8
|
||||
}
|
||||
|
||||
// loadTlsTapper returns the embedded CollectionSpec for tlsTapper.
|
||||
func loadTlsTapper() (*ebpf.CollectionSpec, error) {
|
||||
reader := bytes.NewReader(_TlsTapperBytes)
|
||||
@ -54,6 +77,10 @@ type tlsTapperSpecs struct {
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapperProgramSpecs struct {
|
||||
GolangCryptoTlsWriteUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_write_uprobe"`
|
||||
GolangNetHttpDialconnUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_dialconn_uprobe"`
|
||||
GolangNetHttpReadUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_read_uprobe"`
|
||||
GolangNetSocketUprobe *ebpf.ProgramSpec `ebpf:"golang_net_socket_uprobe"`
|
||||
SslRead *ebpf.ProgramSpec `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.ProgramSpec `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.ProgramSpec `ebpf:"ssl_ret_read"`
|
||||
@ -78,6 +105,9 @@ type tlsTapperMapSpecs struct {
|
||||
ChunksBuffer *ebpf.MapSpec `ebpf:"chunks_buffer"`
|
||||
ConnectSyscallInfo *ebpf.MapSpec `ebpf:"connect_syscall_info"`
|
||||
FileDescriptorToIpv4 *ebpf.MapSpec `ebpf:"file_descriptor_to_ipv4"`
|
||||
GolangDialWrites *ebpf.MapSpec `ebpf:"golang_dial_writes"`
|
||||
GolangReadWrites *ebpf.MapSpec `ebpf:"golang_read_writes"`
|
||||
GolangSocketDials *ebpf.MapSpec `ebpf:"golang_socket_dials"`
|
||||
Heap *ebpf.MapSpec `ebpf:"heap"`
|
||||
LogBuffer *ebpf.MapSpec `ebpf:"log_buffer"`
|
||||
PidsMap *ebpf.MapSpec `ebpf:"pids_map"`
|
||||
@ -108,6 +138,9 @@ type tlsTapperMaps struct {
|
||||
ChunksBuffer *ebpf.Map `ebpf:"chunks_buffer"`
|
||||
ConnectSyscallInfo *ebpf.Map `ebpf:"connect_syscall_info"`
|
||||
FileDescriptorToIpv4 *ebpf.Map `ebpf:"file_descriptor_to_ipv4"`
|
||||
GolangDialWrites *ebpf.Map `ebpf:"golang_dial_writes"`
|
||||
GolangReadWrites *ebpf.Map `ebpf:"golang_read_writes"`
|
||||
GolangSocketDials *ebpf.Map `ebpf:"golang_socket_dials"`
|
||||
Heap *ebpf.Map `ebpf:"heap"`
|
||||
LogBuffer *ebpf.Map `ebpf:"log_buffer"`
|
||||
PidsMap *ebpf.Map `ebpf:"pids_map"`
|
||||
@ -121,6 +154,9 @@ func (m *tlsTapperMaps) Close() error {
|
||||
m.ChunksBuffer,
|
||||
m.ConnectSyscallInfo,
|
||||
m.FileDescriptorToIpv4,
|
||||
m.GolangDialWrites,
|
||||
m.GolangReadWrites,
|
||||
m.GolangSocketDials,
|
||||
m.Heap,
|
||||
m.LogBuffer,
|
||||
m.PidsMap,
|
||||
@ -133,6 +169,10 @@ func (m *tlsTapperMaps) Close() error {
|
||||
//
|
||||
// It can be passed to loadTlsTapperObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapperPrograms struct {
|
||||
GolangCryptoTlsWriteUprobe *ebpf.Program `ebpf:"golang_crypto_tls_write_uprobe"`
|
||||
GolangNetHttpDialconnUprobe *ebpf.Program `ebpf:"golang_net_http_dialconn_uprobe"`
|
||||
GolangNetHttpReadUprobe *ebpf.Program `ebpf:"golang_net_http_read_uprobe"`
|
||||
GolangNetSocketUprobe *ebpf.Program `ebpf:"golang_net_socket_uprobe"`
|
||||
SslRead *ebpf.Program `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.Program `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.Program `ebpf:"ssl_ret_read"`
|
||||
@ -151,6 +191,10 @@ type tlsTapperPrograms struct {
|
||||
|
||||
func (p *tlsTapperPrograms) Close() error {
|
||||
return _TlsTapperClose(
|
||||
p.GolangCryptoTlsWriteUprobe,
|
||||
p.GolangNetHttpDialconnUprobe,
|
||||
p.GolangNetHttpReadUprobe,
|
||||
p.GolangNetSocketUprobe,
|
||||
p.SslRead,
|
||||
p.SslReadEx,
|
||||
p.SslRetRead,
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user