Skip to content

Commit 40334a3

Browse files
iluxaalongir
andauthored
fix: ebpf capture: attach programs on tc hooks after pds created; enable TLS interception in containerized k8s like minikube and kind (#52)
* fix: ebpf capture: attach programs on tc hooks after pds created * enable TLS interception for containerized k8s like minikube and kind * enable TLS interception for containerized k8s like minikube and kind --------- Co-authored-by: Alon Girmonsky <[email protected]>
1 parent b4fee75 commit 40334a3

File tree

9 files changed

+133
-42
lines changed

9 files changed

+133
-42
lines changed

bpf/fd_to_address_tracepoints.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ struct sys_enter_accept4_ctx {
2929

3030
SEC("tracepoint/syscalls/sys_enter_accept4")
3131
void sys_enter_accept4(struct sys_enter_accept4_ctx* ctx) {
32-
__u64 id = bpf_get_current_pid_tgid();
32+
__u64 id = tracer_get_current_pid_tgid();
3333

3434
if (!should_watch(id >> 32)) {
3535
return;
@@ -55,7 +55,7 @@ struct sys_exit_accept4_ctx {
5555

5656
SEC("tracepoint/syscalls/sys_exit_accept4")
5757
void sys_exit_accept4(struct sys_exit_accept4_ctx* ctx) {
58-
__u64 id = bpf_get_current_pid_tgid();
58+
__u64 id = tracer_get_current_pid_tgid();
5959

6060
if (!should_watch(id >> 32)) {
6161
return;
@@ -122,7 +122,7 @@ struct sys_enter_connect_ctx {
122122

123123
SEC("tracepoint/syscalls/sys_enter_connect")
124124
void sys_enter_connect(struct sys_enter_connect_ctx* ctx) {
125-
__u64 id = bpf_get_current_pid_tgid();
125+
__u64 id = tracer_get_current_pid_tgid();
126126

127127
if (!should_watch(id >> 32)) {
128128
return;
@@ -149,7 +149,7 @@ struct sys_exit_connect_ctx {
149149

150150
SEC("tracepoint/syscalls/sys_exit_connect")
151151
void sys_exit_connect(struct sys_exit_connect_ctx* ctx) {
152-
__u64 id = bpf_get_current_pid_tgid();
152+
__u64 id = tracer_get_current_pid_tgid();
153153

154154
if (!should_watch(id >> 32)) {
155155
return;

bpf/fd_tracepoints.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static __always_inline void fd_tracepoints_handle_go(struct sys_enter_read_write
5959

6060
SEC("tracepoint/syscalls/sys_enter_read")
6161
void sys_enter_read(struct sys_enter_read_write_ctx* ctx) {
62-
__u64 id = bpf_get_current_pid_tgid();
62+
__u64 id = tracer_get_current_pid_tgid();
6363

6464
if (!should_watch(id >> 32)) {
6565
return;
@@ -76,7 +76,7 @@ void sys_enter_read(struct sys_enter_read_write_ctx* ctx) {
7676

7777
SEC("tracepoint/syscalls/sys_enter_write")
7878
void sys_enter_write(struct sys_enter_read_write_ctx* ctx) {
79-
__u64 id = bpf_get_current_pid_tgid();
79+
__u64 id = tracer_get_current_pid_tgid();
8080

8181
if (!should_watch(id >> 32)) {
8282
return;
@@ -93,15 +93,15 @@ void sys_enter_write(struct sys_enter_read_write_ctx* ctx) {
9393

9494
SEC("tracepoint/syscalls/sys_exit_read")
9595
void sys_exit_read(struct sys_exit_read_write_ctx* ctx) {
96-
__u64 id = bpf_get_current_pid_tgid();
96+
__u64 id = tracer_get_current_pid_tgid();
9797
// Delete from go map. The value is not used after exiting this syscall.
9898
// Keep value in openssl map.
9999
bpf_map_delete_elem(&go_kernel_read_context, &id);
100100
}
101101

102102
SEC("tracepoint/syscalls/sys_exit_write")
103103
void sys_exit_write(struct sys_exit_read_write_ctx* ctx) {
104-
__u64 id = bpf_get_current_pid_tgid();
104+
__u64 id = tracer_get_current_pid_tgid();
105105
// Delete from go map. The value is not used after exiting this syscall.
106106
// Keep value in openssl map.
107107
bpf_map_delete_elem(&go_kernel_write_context, &id);

bpf/go_uprobes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ static __always_inline int go_crypto_tls_get_fd_from_tcp_conn(struct pt_regs* ct
175175
}
176176

177177
static __always_inline void go_crypto_tls_uprobe(struct pt_regs* ctx, struct bpf_map_def* go_context, enum ABI abi) {
178-
__u64 pid_tgid = bpf_get_current_pid_tgid();
178+
__u64 pid_tgid = tracer_get_current_pid_tgid();
179179
__u64 pid = pid_tgid >> 32;
180180
if (!should_target(pid)) {
181181
return;
@@ -251,7 +251,7 @@ static __always_inline void go_crypto_tls_uprobe(struct pt_regs* ctx, struct bpf
251251
}
252252

253253
static __always_inline void go_crypto_tls_ex_uprobe(struct pt_regs* ctx, struct bpf_map_def* go_context, struct bpf_map_def* go_user_kernel_context, __u32 flags, enum ABI abi) {
254-
__u64 pid_tgid = bpf_get_current_pid_tgid();
254+
__u64 pid_tgid = tracer_get_current_pid_tgid();
255255
__u64 pid = pid_tgid >> 32;
256256
if (!should_target(pid)) {
257257
return;

bpf/include/pids.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,34 @@ int _pid_in_map(struct bpf_map_def* pmap, __u32 pid) {
1919
return shouldTargetGlobally != NULL && *shouldTargetGlobally == 1;
2020
}
2121

22+
const volatile __u64 TRACER_NS_INO = 0;
23+
#define TRACER_NAMESPACES_MAX 4
24+
static __always_inline __u64 tracer_get_current_pid_tgid() {
25+
unsigned int inum;
26+
27+
__u64 base_pid_tgid = bpf_get_current_pid_tgid();
28+
29+
if (TRACER_NS_INO == 0) {
30+
return base_pid_tgid;
31+
}
32+
33+
struct task_struct* task = (struct task_struct*)bpf_get_current_task();
34+
35+
int level = BPF_CORE_READ(task, group_leader, nsproxy, pid_ns_for_children, level);
36+
37+
for (int i = 0; i < TRACER_NAMESPACES_MAX; i++) {
38+
if ((level - i) < 0) {
39+
break;
40+
}
41+
inum = BPF_CORE_READ(task, group_leader, thread_pid, numbers[level - i].ns, ns.inum);
42+
if (inum == TRACER_NS_INO) {
43+
__u64 ret = BPF_CORE_READ(task, group_leader, thread_pid, numbers[level - i].nr);
44+
ret = (ret << 32) | (base_pid_tgid & 0xFFFFFFFF);
45+
return ret;
46+
}
47+
}
48+
return base_pid_tgid;
49+
}
2250

2351
int should_target(__u32 pid) {
2452
return _pid_in_map(&target_pids_map, pid);

bpf/openssl_uprobes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static __always_inline int get_count_bytes(struct pt_regs* ctx, struct ssl_info*
4242
static __always_inline void ssl_uprobe(struct pt_regs* ctx, void* ssl, void* buffer, int num, struct bpf_map_def* map_fd, size_t* count_ptr) {
4343
long err;
4444

45-
__u64 id = bpf_get_current_pid_tgid();
45+
__u64 id = tracer_get_current_pid_tgid();
4646

4747
if (!should_target(id >> 32)) {
4848
return;
@@ -61,7 +61,7 @@ static __always_inline void ssl_uprobe(struct pt_regs* ctx, void* ssl, void* buf
6161
}
6262

6363
static __always_inline void ssl_uretprobe(struct pt_regs* ctx, struct bpf_map_def* map_fd, __u32 flags) {
64-
__u64 id = bpf_get_current_pid_tgid();
64+
__u64 id = tracer_get_current_pid_tgid();
6565

6666
if (!should_target(id >> 32)) {
6767
return;

bpf/tcp_kprobes.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ static void __always_inline tcp_kprobes_forward_openssl(struct ssl_info* info_pt
7979
static __always_inline void tcp_kprobe(struct pt_regs* ctx, struct bpf_map_def* map_fd_openssl, struct bpf_map_def* map_fd_go_kernel, struct bpf_map_def* map_fd_go_user_kernel) {
8080
long err;
8181

82-
__u64 id = bpf_get_current_pid_tgid();
82+
__u64 id = tracer_get_current_pid_tgid();
8383

8484
if (!should_watch(id >> 32)) {
8585
return;
@@ -108,12 +108,12 @@ static __always_inline void tcp_kprobe(struct pt_regs* ctx, struct bpf_map_def*
108108

109109
SEC("kprobe/tcp_sendmsg")
110110
void BPF_KPROBE(tcp_sendmsg) {
111-
__u64 id = bpf_get_current_pid_tgid();
111+
__u64 id = tracer_get_current_pid_tgid();
112112
tcp_kprobe(ctx, &openssl_write_context, &go_kernel_write_context, &go_user_kernel_write_context);
113113
}
114114

115115
SEC("kprobe/tcp_recvmsg")
116116
void BPF_KPROBE(tcp_recvmsg) {
117-
__u64 id = bpf_get_current_pid_tgid();
117+
__u64 id = tracer_get_current_pid_tgid();
118118
tcp_kprobe(ctx, &openssl_read_context, &go_kernel_read_context, &go_user_kernel_read_context);
119119
}

packet_sniffer.go

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,49 @@ import (
1313
type packetFilter struct {
1414
ingressFilterProgram *ebpf.Program
1515
egressFilterProgram *ebpf.Program
16+
ingressPullProgram *ebpf.Program
17+
egressPullProgram *ebpf.Program
1618
attachedPods map[string][2]link.Link
1719
tcClient TcClient
1820
}
1921

2022
func newPacketFilter(ingressFilterProgram, egressFilterProgram, pullIngress, pullEgress *ebpf.Program, pktsRingBuffer *ebpf.Map) (*packetFilter, error) {
21-
var ifaces []int
22-
links, err := netlink.LinkList()
23-
if err != nil {
24-
return nil, err
25-
}
26-
for _, link := range links {
27-
ifaces = append(ifaces, link.Attrs().Index)
28-
}
29-
3023
tcClient := &TcClientImpl{
3124
TcPackage: &TcPackageImpl{},
3225
}
33-
for _, l := range ifaces {
34-
if err := tcClient.SetupTC(l, pullIngress.FD(), pullEgress.FD()); err != nil {
35-
return nil, err
36-
}
37-
}
3826

3927
pf := &packetFilter{
4028
ingressFilterProgram: ingressFilterProgram,
4129
egressFilterProgram: egressFilterProgram,
30+
ingressPullProgram: pullIngress,
31+
egressPullProgram: pullEgress,
4232
attachedPods: make(map[string][2]link.Link),
4333
tcClient: tcClient,
4434
}
35+
pf.update()
4536
return pf, nil
4637
}
4738

39+
func (p *packetFilter) update() {
40+
var ifaces []int
41+
links, err := netlink.LinkList()
42+
if err != nil {
43+
log.Error().Err(err).Msg("Get link list failed:")
44+
return
45+
}
46+
for _, link := range links {
47+
ifaces = append(ifaces, link.Attrs().Index)
48+
}
49+
50+
for _, l := range ifaces {
51+
if err := p.tcClient.SetupTC(l, p.ingressPullProgram.FD(), p.egressPullProgram.FD()); err != nil {
52+
log.Error().Int("link", l).Err(err).Msg("Setup TC failed:")
53+
continue
54+
}
55+
log.Info().Int("link", l).Msg("Attached TC programs:")
56+
}
57+
}
58+
4859
func (p *packetFilter) close() {
4960
_ = p.tcClient.CleanTC()
5061
for uuid := range p.attachedPods {
@@ -64,13 +75,13 @@ func (t *packetFilter) AttachPod(uuid, cgroupV2Path string) error {
6475
return err
6576
}
6677
t.attachedPods[uuid] = [2]link.Link{lIngress, lEgress}
67-
log.Info().Str("pod", uuid).Msg("Attaching pod:") //XXX
78+
log.Info().Str("pod", uuid).Msg("Attaching pod:")
6879

6980
return nil
7081
}
7182

7283
func (t *packetFilter) DetachPod(uuid string) error {
73-
log.Info().Str("pod", uuid).Msg("Detaching pod:") //XXX
84+
log.Info().Str("pod", uuid).Msg("Detaching pod:")
7485
p, ok := t.attachedPods[uuid]
7586
if !ok {
7687
return fmt.Errorf("pod not attached")

tls_process_discoverer.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ type podInfo struct {
2525
var numberRegex = regexp.MustCompile("[0-9]+")
2626

2727
func (t *Tracer) updateTargets(addedWatchedPods []v1.Pod, removedWatchedPods []v1.Pod, addedTargetedPods []v1.Pod, removedTargetedPods []v1.Pod) error {
28+
if t.packetFilter != nil {
29+
t.packetFilter.update()
30+
}
2831
for _, pod := range removedTargetedPods {
2932
if t.packetFilter != nil {
3033
if err := t.packetFilter.DetachPod(string(pod.UID)); err == nil {

tracer.go

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package main
33
import (
44
"fmt"
55

6+
"bytes"
7+
"os"
68
"strconv"
79
"syscall"
810

@@ -50,6 +52,44 @@ type pidOffset struct {
5052
offset uint64
5153
}
5254

55+
type BpfObjectsImpl struct {
56+
bpfObjs tracerObjects
57+
specs *ebpf.CollectionSpec
58+
}
59+
60+
func (objs *BpfObjectsImpl) loadBpfObjects(bpfConstants map[string]uint64) error {
61+
var err error
62+
opts := ebpf.CollectionOptions{
63+
Programs: ebpf.ProgramOptions{
64+
LogSize: ebpf.DefaultVerifierLogSize * 32,
65+
},
66+
}
67+
68+
reader := bytes.NewReader(_TracerBytes)
69+
objs.specs, err = ebpf.LoadCollectionSpecFromReader(reader)
70+
if err != nil {
71+
return err
72+
}
73+
74+
consts := make(map[string]interface{})
75+
for k, v := range bpfConstants {
76+
consts[k] = v
77+
}
78+
err = objs.specs.RewriteConstants(consts)
79+
if err != nil {
80+
return err
81+
}
82+
83+
err = objs.specs.LoadAndAssign(&objs.bpfObjs, &opts)
84+
if err != nil {
85+
var ve *ebpf.VerifierError
86+
if errors.As(err, &ve) {
87+
log.Error().Msg(fmt.Sprintf("Got verifier error: %+v", ve))
88+
}
89+
}
90+
return err
91+
}
92+
5393
func (t *Tracer) Init(
5494
chunksBufferSize int,
5595
logBufferSize int,
@@ -81,25 +121,34 @@ func (t *Tracer) Init(
81121

82122
log.Info().Msg(fmt.Sprintf("Detected Linux kernel version: %s cgroups version: %v", kernelVersion, cgroupsVersion))
83123

84-
t.bpfObjects = tracerObjects{}
85124
// TODO: cilium/ebpf does not support .kconfig Therefore; for now, we load object files according to kernel version.
86125
if kernel.CompareKernelVersion(*kernelVersion, kernel.VersionInfo{Kernel: 4, Major: 6, Minor: 0}) < 1 {
126+
t.bpfObjects = tracerObjects{}
87127
if err := loadTracer46Objects(&t.bpfObjects, nil); err != nil {
88128
return errors.Wrap(err, 0)
89129
}
90130
} else {
91-
opts := ebpf.CollectionOptions{
92-
Programs: ebpf.ProgramOptions{
93-
LogSize: ebpf.DefaultVerifierLogSize * 32,
94-
},
131+
var hostProcIno uint64
132+
fileInfo, err := os.Stat("/hostproc/1/ns/pid")
133+
if err != nil {
134+
// services like "apparmor" on EKS can reject access to system pid information
135+
log.Warn().Err(err).Msg("Get host netns failed")
136+
} else {
137+
hostProcIno = fileInfo.Sys().(*syscall.Stat_t).Ino
138+
log.Info().Uint64("ns", hostProcIno).Msg("Setting host ns")
95139
}
96-
if err := loadTracerObjects(&t.bpfObjects, &opts); err != nil {
97-
var ve *ebpf.VerifierError
98-
if errors.As(err, &ve) {
99-
log.Error().Msg(fmt.Sprintf("Got verifier error: %+v", ve))
100-
}
101-
return errors.Wrap(err, 0)
140+
141+
objs := &BpfObjectsImpl{}
142+
143+
bpfConsts := map[string]uint64{
144+
"TRACER_NS_INO": hostProcIno,
145+
}
146+
err = objs.loadBpfObjects(bpfConsts)
147+
if err != nil {
148+
log.Error().Msg(fmt.Sprintf("load bpf objects failed: %v", err))
149+
return err
102150
}
151+
t.bpfObjects = objs.bpfObjs
103152
}
104153

105154
t.syscallHooks = syscallHooks{}

0 commit comments

Comments
 (0)