Add a uprobe for net/http.(*gzipReader).Read to read chunked HTTP response body

This commit is contained in:
M. Mert Yildiran 2022-06-01 14:32:24 +03:00
parent a2da15ef2d
commit 9fc8e0eb50
No known key found for this signature in database
GPG Key ID: D42ADB236521BF7A
8 changed files with 162 additions and 84 deletions

View File

@ -17,6 +17,7 @@ struct golang_read_write {
__u32 fd;
__u32 conn_addr;
bool is_request;
bool is_gzip_chunk;
__u8 data[BUFFER_SIZE_READ_WRITE];
};
@ -54,6 +55,7 @@ static __always_inline int golang_crypto_tls_write_uprobe(struct pt_regs *ctx) {
// ctx->rsi is common between golang_crypto_tls_write_uprobe and golang_crypto_tls_read_uprobe
b->conn_addr = ctx->rsi; // go.itab.*net.TCPConn,net.Conn address
b->is_request = true;
b->is_gzip_chunk = false;
status = bpf_probe_read_str(&b->data, sizeof(b->data), (void*)ctx->rbx);
if (status < 0) {
@ -80,6 +82,7 @@ static __always_inline int golang_crypto_tls_read_uprobe(struct pt_regs *ctx) {
// ctx->rsi is common between golang_crypto_tls_write_uprobe and golang_crypto_tls_read_uprobe
b->conn_addr = ctx->rsi; // go.itab.*net.TCPConn,net.Conn address
b->is_request = false;
b->is_gzip_chunk = false;
void* stack_addr = (void*)ctx->rsp;
__u64 data_p;
@ -103,6 +106,43 @@ static __always_inline int golang_crypto_tls_read_uprobe(struct pt_regs *ctx) {
return 0;
}
SEC("uprobe/golang_net_http_gzipreader_read")
static __always_inline int golang_net_http_gzipreader_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_crypto_tls_read_uprobe
// b->conn_addr = ctx->rsi; // go.itab.*net.TCPConn,net.Conn address
b->is_request = false;
b->is_gzip_chunk = true;
void* stack_addr = (void*)ctx->rsp;
__u64 data_p;
// Address at ctx->rsp + 0x8 holds the data
__u32 status = bpf_probe_read(&data_p, sizeof(data_p), stack_addr + 0x8);
if (status < 0) {
bpf_printk("[golang_net_http_gzipreader_read_uprobe] error reading data pointer: %d", status);
bpf_ringbuf_discard(b, BPF_RB_FORCE_WAKEUP);
return 0;
}
status = bpf_probe_read_str(&b->data, sizeof(b->data), (void*)(data_p));
if (status < 0) {
bpf_printk("[golang_net_http_gzipreader_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();

View File

@ -10,6 +10,7 @@ type golangHooks struct {
golangSocketProbe link.Link
golangWriteProbe link.Link
golangReadProbe link.Link
golangGzipProbe link.Link
}
func (s *golangHooks) installUprobes(bpfObjects *tlsTapperObjects, filePath string) error {
@ -71,6 +72,16 @@ func (s *golangHooks) installHooks(bpfObjects *tlsTapperObjects, ex *link.Execut
return errors.Wrap(err, 0)
}
// Relative offset points to
// [`net/http.(*gzipReader).Read+363`](https://github.com/golang/go/blob/fe4de36198794c447fbd9d7cc2d7199a506c76a5/src/net/http/transport.go#L2837)
s.golangGzipProbe, err = ex.Uprobe(golangReadSymbol, bpfObjects.GolangNetHttpGzipreaderReadUprobe, &link.UprobeOptions{
Offset: offsets.GolangGzipOffset + 0x16b,
})
if err != nil {
return errors.Wrap(err, 0)
}
return nil
}
@ -93,5 +104,9 @@ func (s *golangHooks) close() []error {
errors = append(errors, err)
}
if err := s.golangGzipProbe.Close(); err != nil {
errors = append(errors, err)
}
return errors
}

View File

@ -15,6 +15,7 @@ type golangOffsets struct {
GolangSocketOffset uint64
GolangWriteOffset uint64
GolangReadOffset uint64
GolangGzipOffset uint64
}
const (
@ -22,6 +23,7 @@ const (
golangVersionSymbol = "runtime.buildVersion.str"
golangWriteSymbol = "crypto/tls.(*Conn).Write"
golangReadSymbol = "crypto/tls.(*Conn).Read"
golangGzipSymbol = "net/http.(*gzipReader).Read"
golangSocketSymbol = "net.socket"
golangDialSymbol = "net/http.(*Transport).dialConn"
)
@ -66,11 +68,17 @@ func findGolangOffsets(filePath string) (golangOffsets, error) {
return golangOffsets{}, fmt.Errorf("reading offset [%s]: %s", golangReadSymbol, err)
}
gzipOffset, err := getOffset(offsets, golangGzipSymbol)
if err != nil {
return golangOffsets{}, fmt.Errorf("reading offset [%s]: %s", golangGzipSymbol, err)
}
return golangOffsets{
GolangDialOffset: dialOffset,
GolangSocketOffset: socketOffset,
GolangWriteOffset: writeOffset,
GolangReadOffset: readOffset,
GolangGzipOffset: gzipOffset,
}, nil
}

View File

@ -22,6 +22,7 @@ import (
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/tap/api"
orderedmap "github.com/wk8/go-ordered-map"
"golang.org/x/sys/unix"
)
const (
@ -137,6 +138,12 @@ func (p *tlsPoller) pollGolangReadWrite(rd *ringbuf.Reader, emitter api.Emitter,
continue
}
if b.IsGzipChunk {
chunk := unix.ByteSliceToString(b.Data[:])
fmt.Printf("chunk: %v\n", chunk)
continue
}
if p.golangReadWriteMap.Len()+1 > golangMapLimit {
pair := p.golangReadWriteMap.Oldest()
p.golangReadWriteMap.Delete(pair.Key)

View File

@ -14,12 +14,13 @@ import (
)
type tlsTapperGolangReadWrite struct {
Pid uint32
Fd uint32
ConnAddr uint32
IsRequest bool
Data [524288]uint8
_ [3]byte
Pid uint32
Fd uint32
ConnAddr uint32
IsRequest bool
IsGzipChunk bool
Data [524288]uint8
_ [2]byte
}
type tlsTapperTlsChunk struct {
@ -75,24 +76,25 @@ type tlsTapperSpecs struct {
//
// It can be passed ebpf.CollectionSpec.Assign.
type tlsTapperProgramSpecs struct {
GolangCryptoTlsReadUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_read_uprobe"`
GolangCryptoTlsWriteUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_write_uprobe"`
GolangNetHttpDialconnUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_dialconn_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"`
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
GolangCryptoTlsReadUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_read_uprobe"`
GolangCryptoTlsWriteUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_write_uprobe"`
GolangNetHttpDialconnUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_dialconn_uprobe"`
GolangNetHttpGzipreaderReadUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_gzipreader_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"`
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
}
// tlsTapperMapSpecs contains maps before they are loaded into the kernel.
@ -167,24 +169,25 @@ func (m *tlsTapperMaps) Close() error {
//
// It can be passed to loadTlsTapperObjects or ebpf.CollectionSpec.LoadAndAssign.
type tlsTapperPrograms struct {
GolangCryptoTlsReadUprobe *ebpf.Program `ebpf:"golang_crypto_tls_read_uprobe"`
GolangCryptoTlsWriteUprobe *ebpf.Program `ebpf:"golang_crypto_tls_write_uprobe"`
GolangNetHttpDialconnUprobe *ebpf.Program `ebpf:"golang_net_http_dialconn_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"`
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
SslWrite *ebpf.Program `ebpf:"ssl_write"`
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
GolangCryptoTlsReadUprobe *ebpf.Program `ebpf:"golang_crypto_tls_read_uprobe"`
GolangCryptoTlsWriteUprobe *ebpf.Program `ebpf:"golang_crypto_tls_write_uprobe"`
GolangNetHttpDialconnUprobe *ebpf.Program `ebpf:"golang_net_http_dialconn_uprobe"`
GolangNetHttpGzipreaderReadUprobe *ebpf.Program `ebpf:"golang_net_http_gzipreader_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"`
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
SslWrite *ebpf.Program `ebpf:"ssl_write"`
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
}
func (p *tlsTapperPrograms) Close() error {
@ -192,6 +195,7 @@ func (p *tlsTapperPrograms) Close() error {
p.GolangCryptoTlsReadUprobe,
p.GolangCryptoTlsWriteUprobe,
p.GolangNetHttpDialconnUprobe,
p.GolangNetHttpGzipreaderReadUprobe,
p.GolangNetSocketUprobe,
p.SslRead,
p.SslReadEx,

Binary file not shown.

View File

@ -14,12 +14,13 @@ import (
)
type tlsTapperGolangReadWrite struct {
Pid uint32
Fd uint32
ConnAddr uint32
IsRequest bool
Data [524288]uint8
_ [3]byte
Pid uint32
Fd uint32
ConnAddr uint32
IsRequest bool
IsGzipChunk bool
Data [524288]uint8
_ [2]byte
}
type tlsTapperTlsChunk struct {
@ -75,24 +76,25 @@ type tlsTapperSpecs struct {
//
// It can be passed ebpf.CollectionSpec.Assign.
type tlsTapperProgramSpecs struct {
GolangCryptoTlsReadUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_read_uprobe"`
GolangCryptoTlsWriteUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_write_uprobe"`
GolangNetHttpDialconnUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_dialconn_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"`
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
GolangCryptoTlsReadUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_read_uprobe"`
GolangCryptoTlsWriteUprobe *ebpf.ProgramSpec `ebpf:"golang_crypto_tls_write_uprobe"`
GolangNetHttpDialconnUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_dialconn_uprobe"`
GolangNetHttpGzipreaderReadUprobe *ebpf.ProgramSpec `ebpf:"golang_net_http_gzipreader_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"`
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
}
// tlsTapperMapSpecs contains maps before they are loaded into the kernel.
@ -167,24 +169,25 @@ func (m *tlsTapperMaps) Close() error {
//
// It can be passed to loadTlsTapperObjects or ebpf.CollectionSpec.LoadAndAssign.
type tlsTapperPrograms struct {
GolangCryptoTlsReadUprobe *ebpf.Program `ebpf:"golang_crypto_tls_read_uprobe"`
GolangCryptoTlsWriteUprobe *ebpf.Program `ebpf:"golang_crypto_tls_write_uprobe"`
GolangNetHttpDialconnUprobe *ebpf.Program `ebpf:"golang_net_http_dialconn_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"`
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
SslWrite *ebpf.Program `ebpf:"ssl_write"`
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
GolangCryptoTlsReadUprobe *ebpf.Program `ebpf:"golang_crypto_tls_read_uprobe"`
GolangCryptoTlsWriteUprobe *ebpf.Program `ebpf:"golang_crypto_tls_write_uprobe"`
GolangNetHttpDialconnUprobe *ebpf.Program `ebpf:"golang_net_http_dialconn_uprobe"`
GolangNetHttpGzipreaderReadUprobe *ebpf.Program `ebpf:"golang_net_http_gzipreader_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"`
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
SslWrite *ebpf.Program `ebpf:"ssl_write"`
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
}
func (p *tlsTapperPrograms) Close() error {
@ -192,6 +195,7 @@ func (p *tlsTapperPrograms) Close() error {
p.GolangCryptoTlsReadUprobe,
p.GolangCryptoTlsWriteUprobe,
p.GolangNetHttpDialconnUprobe,
p.GolangNetHttpGzipreaderReadUprobe,
p.GolangNetSocketUprobe,
p.SslRead,
p.SslReadEx,

Binary file not shown.