-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #100 from chenhengqi/golang-https
Support Golang HTTPS introspection Only support x86_64 `Conn.Write()` . TODO : support arm64 and `Conn.Read()`
- Loading branch information
Showing
11 changed files
with
448 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,3 +17,5 @@ | |
|
||
# VSCode | ||
.vscode/settings.json | ||
|
||
kern/bpf/x86/vmlinux.h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/* Copyright © 2022 Hengqi Chen */ | ||
#include "ecapture.h" | ||
|
||
struct go_ssl_event { | ||
__u64 ts_ns; | ||
__u32 pid; | ||
__u32 tid; | ||
int data_len; | ||
char comm[TASK_COMM_LEN]; | ||
char data[MAX_DATA_SIZE_OPENSSL]; | ||
}; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); | ||
} events SEC(".maps"); | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); | ||
__type(key, __u32); | ||
__type(value, struct go_ssl_event); | ||
__uint(max_entries, 1); | ||
} heap SEC(".maps"); | ||
|
||
#ifndef NOCORE | ||
|
||
#if defined(__TARGET_ARCH_x86) | ||
#define GO_REG1(x) BPF_CORE_READ((x), ax) | ||
#define GO_REG2(x) BPF_CORE_READ((x), bx) | ||
#define GO_REG3(x) BPF_CORE_READ((x), cx) | ||
#define GO_REG4(x) BPF_CORE_READ((x), di) | ||
#define GO_SP(x) BPF_CORE_READ((x), sp) | ||
#elif defined(__TARGET_ARCH_arm64) | ||
#define GO_REG1(x) PT_REGS_PARM1_CORE(x) | ||
#define GO_REG2(x) PT_REGS_PARM2_CORE(x) | ||
#define GO_REG3(x) PT_REGS_PARM3_CORE(x) | ||
#define GO_REG4(x) PT_REGS_PARM4_CORE(x) | ||
#define GO_SP(x) PT_REGS_SP_CORE(x) | ||
#endif | ||
|
||
#else | ||
|
||
#if defined(__x86_64__) | ||
#define GO_REG1(x) ((x)->ax) | ||
#define GO_REG2(x) ((x)->bx) | ||
#define GO_REG3(x) ((x)->cx) | ||
#define GO_REG4(x) ((x)->di) | ||
#define GO_SP(x) ((x)->sp) | ||
#elif defined(__aarch64__) | ||
#define GO_REG1(x) PT_REGS_PARM1(x) | ||
#define GO_REG2(x) PT_REGS_PARM2(x) | ||
#define GO_REG3(x) PT_REGS_PARM3(x) | ||
#define GO_REG4(x) PT_REGS_PARM4(x) | ||
#define GO_SP(x) PT_REGS_SP(x) | ||
#endif | ||
|
||
#endif | ||
|
||
static struct go_ssl_event *get_event() | ||
{ | ||
static const int zero = 0; | ||
struct go_ssl_event *event; | ||
__u64 id; | ||
|
||
event = bpf_map_lookup_elem(&heap, &zero); | ||
if (!event) | ||
return NULL; | ||
|
||
id = bpf_get_current_pid_tgid(); | ||
event->ts_ns = bpf_ktime_get_ns(); | ||
event->pid = id >> 32; | ||
event->tid = (__u32)id; | ||
bpf_get_current_comm(event->comm, sizeof(event->comm)); | ||
return event; | ||
} | ||
|
||
SEC("uprobe/abi_stack") | ||
int BPF_KPROBE(probe_stack) | ||
{ | ||
struct go_ssl_event *event; | ||
__u64 *sp = (void *)GO_SP(ctx), addr; | ||
int len, record_type; | ||
const char *str; | ||
|
||
bpf_probe_read_user(&record_type, sizeof(record_type), sp + 2); | ||
if (record_type != 23) | ||
return 0; | ||
|
||
bpf_probe_read_user(&addr, sizeof(addr), sp + 3); | ||
bpf_probe_read_user(&len, sizeof(len), sp + 4); | ||
|
||
event = get_event(); | ||
if (!event) | ||
return 0; | ||
|
||
str = (void *)addr; | ||
bpf_probe_read_user_str(event->data, sizeof(event->data), str); | ||
event->data_len = len; | ||
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(*event)); | ||
return 0; | ||
} | ||
|
||
SEC("uprobe/abi_register") | ||
int BPF_KPROBE(probe_register) | ||
{ | ||
struct go_ssl_event *event; | ||
int len, record_type; | ||
const char *str; | ||
|
||
record_type = GO_REG2(ctx); | ||
str = (void *)GO_REG3(ctx); | ||
len = GO_REG4(ctx); | ||
|
||
if (record_type != 23) | ||
return 0; | ||
|
||
event = get_event(); | ||
if (!event) | ||
return 0; | ||
|
||
bpf_probe_read_user_str(event->data, sizeof(event->data), str); | ||
event->data_len = len; | ||
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(*event)); | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package proc | ||
|
||
import ( | ||
"debug/dwarf" | ||
"debug/elf" | ||
"errors" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
const ( | ||
goVersionPrefix = "Go cmd/compile " | ||
) | ||
|
||
// ErrVersionNotFound is returned when we can't find Go version info from a binary | ||
var ErrVersionNotFound = errors.New("version info not found") | ||
|
||
// GoVersion represents Go toolchain version that a binary is built with. | ||
type GoVersion struct { | ||
major int | ||
minor int | ||
} | ||
|
||
// After returns true if it is greater than major.minor | ||
func (v *GoVersion) After(major, minor int) bool { | ||
if v.major > minor { | ||
return true | ||
} | ||
if v.major == major && v.minor > minor { | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
// ExtraceGoVersion extracts Go version info from a binary that is built with Go toolchain | ||
func ExtraceGoVersion(path string) (*GoVersion, error) { | ||
file, err := elf.Open(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer file.Close() | ||
|
||
raw, err := file.DWARF() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
reader := raw.Reader() | ||
for { | ||
entry, err := reader.Next() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if entry == nil { | ||
break | ||
} | ||
|
||
for _, field := range entry.Field { | ||
if field.Attr == dwarf.AttrProducer { | ||
val, ok := field.Val.(string) | ||
if !ok { | ||
continue | ||
} | ||
return parseGoVersion(val) | ||
} | ||
} | ||
} | ||
|
||
return nil, ErrVersionNotFound | ||
} | ||
|
||
func parseGoVersion(r string) (*GoVersion, error) { | ||
ver := strings.TrimPrefix(r, goVersionPrefix) | ||
|
||
if strings.HasPrefix(ver, "go") { | ||
v := strings.SplitN(ver[2:], ".", 3) | ||
var major, minor int | ||
var err error | ||
|
||
major, err = strconv.Atoi(v[0]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if len(v) >= 2 { | ||
minor, err = strconv.Atoi(v[1]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
return &GoVersion{ | ||
major: major, | ||
minor: minor, | ||
}, nil | ||
} | ||
return nil, ErrVersionNotFound | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package proc | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"testing" | ||
) | ||
|
||
func TestExtraceGoVersion(t *testing.T) { | ||
path := fmt.Sprintf("/proc/%d/exe", os.Getppid()) | ||
ver, err := ExtraceGoVersion(path) | ||
if err != nil { | ||
t.Log(err) | ||
return | ||
} | ||
log.Println(ver) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright © 2022 Hengqi Chen | ||
package user | ||
|
||
import ( | ||
"errors" | ||
"os" | ||
) | ||
|
||
// GoSSLConfig represents configuration for Go SSL probe | ||
type GoSSLConfig struct { | ||
eConfig | ||
Path string | ||
} | ||
|
||
// NewGoSSLConfig creates a new config for Go SSL | ||
func NewGoSSLConfig() *GoSSLConfig { | ||
return &GoSSLConfig{} | ||
} | ||
|
||
func (c *GoSSLConfig) Check() error { | ||
if c.Path == "" { | ||
return errors.New("go binary not found") | ||
} | ||
_, err := os.Stat(c.Path) | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.