Skip to content

Commit d102fc8

Browse files
committed
Initial PR to implement openSSL userspace tracker
Signed-off-by: Mohamed S. Mahmoud <[email protected]> (cherry picked from commit 49444b1)
1 parent 7519f04 commit d102fc8

21 files changed

+484
-11
lines changed

.mk/bc.mk

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ define PROGRAMS
2222
"xfrm_input_kprobe": "kprobe",
2323
"xfrm_input_kretprobe": "kretprobe",
2424
"xfrm_output_kprobe": "kprobe",
25-
"xfrm_output_kretprobe": "kretprobe"
25+
"xfrm_output_kretprobe": "kretprobe",
26+
"probe_entry_SSL_write":"uprobe",
27+
"probe_exit_SSL_write":"uretprobe"
2628
}
2729
endef
2830

@@ -38,7 +40,9 @@ define MAPS
3840
"filter_map":"lpm_trie",
3941
"peer_filter_map":"lpm_trie",
4042
"ipsec_ingress_map":"hash",
41-
"ipsec_egress_map":"hash"
43+
"ipsec_egress_map":"hash",
44+
"active_ssl_write_map":"hash",
45+
"ssl_data_event_map":"ringbuf"
4246
}
4347
endef
4448

bpf/configs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ volatile const u8 enable_network_events_monitoring = 0;
1515
volatile const u8 network_events_monitoring_groupid = 0;
1616
volatile const u8 enable_pkt_translation_tracking = 0;
1717
volatile const u8 enable_ipsec = 0;
18+
volatile const u8 enable_ssl = 0;
1819
#endif //__CONFIGS_H__

bpf/flows.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@
5757
*/
5858
#include "ipsec.h"
5959

60+
/*
61+
* Defines ssl tracker
62+
*/
63+
#include "openssl_tracker.h"
64+
6065
// return 0 on success, 1 if capacity reached
6166
static __always_inline int add_observed_intf(flow_metrics *value, pkt_info *pkt, u32 if_index,
6267
u8 direction) {

bpf/maps_definition.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,20 @@ struct {
9797
__uint(pinning, LIBBPF_PIN_BY_NAME);
9898
} ipsec_egress_map SEC(".maps");
9999

100+
// HashMap to store active SSL write args
101+
struct {
102+
__uint(type, BPF_MAP_TYPE_HASH);
103+
__type(key, u64);
104+
__type(value, struct active_ssl_buf_t);
105+
__uint(map_flags, BPF_F_NO_PREALLOC);
106+
__uint(pinning, LIBBPF_PIN_BY_NAME);
107+
} active_ssl_write_map SEC(".maps");
108+
109+
// Ringbuf for SSL data events
110+
struct {
111+
__uint(type, BPF_MAP_TYPE_RINGBUF);
112+
__uint(max_entries, 1 << 27); // 16KB * 1000 events/sec * 5sec "eviction time" = ~128MB
113+
__uint(pinning, LIBBPF_PIN_BY_NAME);
114+
} ssl_data_event_map SEC(".maps");
115+
100116
#endif //__MAPS_DEFINITION_H__

bpf/openssl_tracker.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* OpenSSL monitoring uprobe/uretprobe eBPF hook.
3+
*/
4+
5+
#ifndef __OPENSSL_TRACKER_H__
6+
#define __OPENSSL_TRACKER_H__
7+
8+
#include "utils.h"
9+
10+
static inline void generate_SSL_data_event(struct pt_regs *ctx, u64 pid_tgid, u8 ssl_type,
11+
const char *buf) {
12+
int len = (int)PT_REGS_RC(ctx);
13+
if (len < 0) {
14+
return;
15+
}
16+
17+
struct ssl_data_event_t *event;
18+
event = bpf_ringbuf_reserve(&ssl_data_event_map, sizeof(*event), 0);
19+
if (!event) {
20+
return;
21+
}
22+
event->timestamp_ns = bpf_ktime_get_ns();
23+
event->pid_tgid = pid_tgid;
24+
event->ssl_type = ssl_type;
25+
event->data_len = len < MAX_DATA_SIZE_OPENSSL ? len : MAX_DATA_SIZE_OPENSSL;
26+
bpf_probe_read_user(&event->data, event->data_len, buf);
27+
bpf_ringbuf_submit(event, 0);
28+
}
29+
30+
// int SSL_write(SSL *ssl, const void *buf, int num);
31+
// https://github.com/openssl/openssl/blob/master/ssl/ssl_lib.c#L2666
32+
SEC("uprobe/SSL_write")
33+
int probe_entry_SSL_write(struct pt_regs *ctx) {
34+
if (do_sampling == 0 || enable_ssl == 0) {
35+
return 0;
36+
}
37+
38+
u64 pid_tgid = bpf_get_current_pid_tgid();
39+
40+
BPF_PRINTK("openssl uprobe/SSL_write pid: %d\n", pid_tgid);
41+
// https://github.com/openssl/openssl/blob/master/ssl/ssl_local.h#L1233
42+
void *ssl = (void *)PT_REGS_PARM1(ctx);
43+
44+
u32 ssl_type;
45+
int ret;
46+
47+
ret = bpf_probe_read_user(&ssl_type, sizeof(ssl_type), (u32 *)ssl);
48+
if (ret) {
49+
BPF_PRINTK("(OPENSSL) bpf_probe_read ssl_type_ptr failed, ret: %d\n", ret);
50+
return 0;
51+
}
52+
const char *buf = (const char *)PT_REGS_PARM2(ctx);
53+
54+
BPF_PRINTK("openssl uprobe/SSL_write type: %d, buf: %p\n", ssl_type, buf);
55+
56+
struct active_ssl_buf_t active_ssl_buf_t;
57+
__builtin_memset(&active_ssl_buf_t, 0, sizeof(active_ssl_buf_t));
58+
active_ssl_buf_t.ssl_type = ssl_type;
59+
bpf_probe_read_user(&active_ssl_buf_t.buf, sizeof(active_ssl_buf_t.buf), buf);
60+
61+
ret = bpf_map_update_elem(&active_ssl_write_map, &pid_tgid, &active_ssl_buf_t, BPF_NOEXIST);
62+
if (ret != 0) {
63+
if (trace_messages) {
64+
BPF_PRINTK("error creating new active_ssl_write_map dir: %d err: %d\n", pid_tgid, ret);
65+
}
66+
}
67+
return 0;
68+
}
69+
70+
SEC("uretprobe/SSL_write")
71+
int probe_exit_SSL_write(struct pt_regs *ctx) {
72+
if (do_sampling == 0 || enable_ssl == 0) {
73+
return 0;
74+
}
75+
u64 pid_tgid = bpf_get_current_pid_tgid();
76+
77+
struct active_ssl_buf_t *active_ssl_buf = bpf_map_lookup_elem(&active_ssl_write_map, &pid_tgid);
78+
if (active_ssl_buf != NULL) {
79+
u8 ssl_type = active_ssl_buf->ssl_type;
80+
generate_SSL_data_event(ctx, pid_tgid, ssl_type, (const char *)active_ssl_buf->buf);
81+
bpf_map_delete_elem(&active_ssl_write_map, &pid_tgid);
82+
}
83+
return 0;
84+
}
85+
86+
#endif /* __OPENSSL_TRACKER_H__ */

bpf/types.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,26 @@ struct filter_value_t {
277277
// Force emitting enums/structs into the ELF
278278
const static struct filter_value_t *unused12 __attribute__((unused));
279279

280+
// Active SSL write args
281+
struct active_ssl_buf_t {
282+
u8 ssl_type;
283+
u8 buf[MAX_PAYLOAD_SIZE];
284+
} active_ssl_buf;
285+
286+
// Force emitting enums/structs into the ELF
287+
const static struct active_ssl_buf_t *unused13 __attribute__((unused));
288+
289+
#define MAX_DATA_SIZE_OPENSSL 1024 * 16
290+
// SSL data event
291+
struct ssl_data_event_t {
292+
u64 timestamp_ns;
293+
u64 pid_tgid;
294+
char data[MAX_DATA_SIZE_OPENSSL];
295+
s32 data_len;
296+
u8 ssl_type;
297+
} ssl_data_event;
298+
299+
// Force emitting enums/structs into the ELF
300+
const static struct ssl_data_event_t *unused14 __attribute__((unused));
301+
280302
#endif /* __TYPES_H__ */

pkg/agent/agent.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ type Flows struct {
8686
promoServer *http.Server
8787
sampleDecoder *ovnobserv.SampleDecoder
8888

89-
metrics *metrics.Metrics
89+
metrics *metrics.Metrics
90+
rbSSLTracer *flow.RingBufTracer
9091
}
9192

9293
// ebpfFlowFetcher abstracts the interface of ebpf.FlowFetcher to allow dependency injection in tests
@@ -97,6 +98,7 @@ type ebpfFlowFetcher interface {
9798
LookupAndDeleteMap(*metrics.Metrics) map[ebpf.BpfFlowId]model.BpfFlowContent
9899
DeleteMapsStaleEntries(timeOut time.Duration)
99100
ReadRingBuf() (ringbuf.Record, error)
101+
ReadSSLRingBuf() (ringbuf.Record, error)
100102
}
101103

102104
// FlowsAgent instantiates a new agent, given a configuration.
@@ -175,6 +177,8 @@ func FlowsAgent(cfg *config.Agent) (*Flows, error) {
175177
BpfManBpfFSPath: cfg.BpfManBpfFSPath,
176178
EnableIPsecTracker: cfg.EnableIPsecTracking,
177179
FilterConfig: filterRules,
180+
EnableSSL: cfg.EnableSSL,
181+
OpenSSLPath: cfg.OpenSSLPath,
178182
}
179183

180184
fetcher, err := tracer.NewFlowFetcher(ebpfConfig, m)
@@ -206,6 +210,10 @@ func flowsAgent(
206210

207211
mapTracer := flow.NewMapTracer(fetcher, cfg.CacheActiveTimeout, cfg.StaleEntriesEvictTimeout, m, s, cfg.EnableUDNMapping)
208212
rbTracer := flow.NewRingBufTracer(fetcher, mapTracer, cfg.CacheActiveTimeout, m)
213+
var rbSSLTracer *flow.RingBufTracer
214+
if cfg.EnableSSL {
215+
rbSSLTracer = flow.NewSSLRingBufTracer(fetcher, mapTracer, cfg.CacheActiveTimeout, m)
216+
}
209217
accounter := flow.NewAccounter(cfg.CacheMaxFlows, cfg.CacheActiveTimeout, time.Now, monotime.Now, m, s, cfg.EnableUDNMapping)
210218
limiter := flow.NewCapacityLimiter(m)
211219

@@ -222,6 +230,7 @@ func flowsAgent(
222230
informer: informer,
223231
promoServer: promoServer,
224232
metrics: m,
233+
rbSSLTracer: rbSSLTracer,
225234
}, nil
226235
}
227236

@@ -392,6 +401,10 @@ func (f *Flows) buildAndStartPipeline(ctx context.Context) (*node.Terminal[[]*mo
392401
alog.Debug("connecting flows processing graph")
393402
mapTracer := node.AsStart(f.mapTracer.TraceLoop(ctx, f.cfg.ForceGC))
394403
rbTracer := node.AsStart(f.rbTracer.TraceLoop(ctx))
404+
var rbSSLTracer *node.Start[*model.RawRecord]
405+
if f.cfg.EnableSSL {
406+
rbSSLTracer = node.AsStart(f.rbSSLTracer.TraceLoop(ctx))
407+
}
395408

396409
accounter := node.AsMiddle(f.accounter.Account,
397410
node.ChannelBufferLen(f.cfg.BuffersLength))
@@ -408,6 +421,9 @@ func (f *Flows) buildAndStartPipeline(ctx context.Context) (*node.Terminal[[]*mo
408421
node.ChannelBufferLen(ebl))
409422

410423
rbTracer.SendsTo(accounter)
424+
if rbSSLTracer != nil {
425+
rbSSLTracer.SendsTo(accounter)
426+
}
411427

412428
mapTracer.SendsTo(limiter)
413429
accounter.SendsTo(limiter)
@@ -416,6 +432,9 @@ func (f *Flows) buildAndStartPipeline(ctx context.Context) (*node.Terminal[[]*mo
416432
alog.Debug("starting graph")
417433
mapTracer.Start()
418434
rbTracer.Start()
435+
if rbSSLTracer != nil {
436+
rbSSLTracer.Start()
437+
}
419438
return export, nil
420439
}
421440

pkg/config/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ type Agent struct {
252252
// This setting is only used when the interface name could not be found for a given index and MAC.
253253
// E.g. "0a:58=eth0" (used for ovn-kubernetes)
254254
PreferredInterfaceForMACPrefix string `env:"PREFERRED_INTERFACE_FOR_MAC_PREFIX"`
255+
// EnableSSL enable tracking SSL flows encryption
256+
EnableSSL bool `env:"ENABLE_SSL" envDefault:"false"`
257+
// OpenSSLPath path to the openssl binary
258+
OpenSSLPath string `env:"OPENSSL_PATH" envDefault:"/usr/bin/openssl"`
255259

256260
/* Deprecated configs are listed below this line
257261
* See manageDeprecatedConfigs function for details

0 commit comments

Comments
 (0)