mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-02-04 10:44:14 +08:00
248 lines
7.5 KiB
C
248 lines
7.5 KiB
C
#include "openssl_trace.bpf.h"
|
|
|
|
enum ssl_data_event_type { kSSLRead, kSSLWrite };
|
|
const u32 invalidFD = 0;
|
|
|
|
struct ssl_data_event_t {
|
|
enum ssl_data_event_type type;
|
|
u64 timestamp_ns;
|
|
u32 pid;
|
|
u32 tid;
|
|
char data[MAX_DATA_SIZE_OPENSSL];
|
|
s32 data_len;
|
|
char comm[TASK_COMM_LEN];
|
|
u32 fd;
|
|
};
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
|
} tls_events SEC(".maps");
|
|
|
|
struct active_ssl_buf {
|
|
u32 fd;
|
|
const char* buf;
|
|
};
|
|
|
|
// BPF programs are limited to a 512-byte stack. We store this value per CPU
|
|
// and use it as a heap allocated value.
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
|
__type(key, u32);
|
|
__type(value, struct ssl_data_event_t);
|
|
__uint(max_entries, 1);
|
|
} data_buffer_heap SEC(".maps");
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_HASH);
|
|
__type(key, u64);
|
|
__type(value, struct active_ssl_buf);
|
|
__uint(max_entries, 1024);
|
|
} active_ssl_read_args_map SEC(".maps");
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_HASH);
|
|
__type(key, u64);
|
|
__type(value, struct active_ssl_buf);
|
|
__uint(max_entries, 1024);
|
|
} active_ssl_write_args_map SEC(".maps");
|
|
|
|
// OPENSSL struct to offset , via kern/README.md
|
|
typedef long (*unused_fn)();
|
|
|
|
struct unused {};
|
|
|
|
struct BIO {
|
|
const struct unused* method;
|
|
unused_fn callback;
|
|
unused_fn callback_ex;
|
|
char* cb_arg; /* first argument for the callback */
|
|
int init;
|
|
int shutdown;
|
|
int flags; /* extra storage */
|
|
int retry_reason;
|
|
int num;
|
|
};
|
|
|
|
struct ssl_st {
|
|
int version;
|
|
struct unused* method;
|
|
struct BIO* rbio; // used by SSL_read
|
|
struct BIO* wbio; // used by SSL_write
|
|
};
|
|
|
|
/***********************************************************
|
|
* General helper functions
|
|
***********************************************************/
|
|
static __inline struct ssl_data_event_t* create_ssl_data_event(
|
|
u64 current_pid_tgid) {
|
|
u32 kZero = 0;
|
|
struct ssl_data_event_t* event =
|
|
bpf_map_lookup_elem(&data_buffer_heap, &kZero);
|
|
if (event == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
const u32 kMask32b = 0xffffffff;
|
|
event->timestamp_ns = bpf_ktime_get_ns();
|
|
event->pid = current_pid_tgid >> 32;
|
|
event->tid = current_pid_tgid & kMask32b;
|
|
event->fd = invalidFD;
|
|
|
|
return event;
|
|
}
|
|
|
|
/***********************************************************
|
|
* BPF syscall processing functions
|
|
***********************************************************/
|
|
static int process_SSL_data(struct pt_regs* ctx, u64 id,
|
|
enum ssl_data_event_type type, const char* buf,
|
|
u32 fd) {
|
|
int len = (int)PT_REGS_RC(ctx);
|
|
if (len < 0) {
|
|
return 0;
|
|
}
|
|
|
|
struct ssl_data_event_t* event = create_ssl_data_event(id);
|
|
if (event == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
event->type = type;
|
|
event->fd = fd;
|
|
// This is a max function, but it is written in such a way to keep older BPF
|
|
// verifiers happy.
|
|
event->data_len =
|
|
(len < MAX_DATA_SIZE_OPENSSL ? (len & (MAX_DATA_SIZE_OPENSSL - 1))
|
|
: MAX_DATA_SIZE_OPENSSL);
|
|
bpf_probe_read(event->data, event->data_len, buf);
|
|
bpf_get_current_comm(&event->comm, sizeof(event->comm));
|
|
bpf_perf_event_output(ctx, &tls_events, BPF_F_CURRENT_CPU, event,
|
|
sizeof(struct ssl_data_event_t));
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************
|
|
* BPF probe function entry-points
|
|
***********************************************************/
|
|
|
|
// Function signature being probed:
|
|
// int SSL_write(SSL *ssl, const void *buf, int num);
|
|
SEC("uprobe/SSL_write")
|
|
int probe_entry_SSL_write(struct pt_regs* ctx) {
|
|
u64 current_pid_tgid = bpf_get_current_pid_tgid();
|
|
u32 pid = current_pid_tgid >> 32;
|
|
|
|
#ifndef KERNEL_LESS_5_2
|
|
// if target_ppid is 0 then we target all pids
|
|
if (target_pid != 0 && target_pid != pid) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
// debug_bpf_printk("openssl uprobe/SSL_write pid :%d\n", pid);
|
|
|
|
void* ssl = (void*)PT_REGS_PARM1(ctx);
|
|
// https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/bio/bio_local.h
|
|
struct ssl_st ssl_info;
|
|
bpf_probe_read_user(&ssl_info, sizeof(ssl_info), ssl);
|
|
|
|
struct BIO bio_w;
|
|
bpf_probe_read_user(&bio_w, sizeof(bio_w), ssl_info.wbio);
|
|
|
|
// get fd ssl->wbio->num
|
|
u32 fd = bio_w.num;
|
|
// debug_bpf_printk("openssl uprobe SSL_write FD:%d\n", fd);
|
|
|
|
const char* buf = (const char*)PT_REGS_PARM2(ctx);
|
|
struct active_ssl_buf active_ssl_buf_t;
|
|
__builtin_memset(&active_ssl_buf_t, 0, sizeof(active_ssl_buf_t));
|
|
active_ssl_buf_t.fd = fd;
|
|
active_ssl_buf_t.buf = buf;
|
|
bpf_map_update_elem(&active_ssl_write_args_map, ¤t_pid_tgid,
|
|
&active_ssl_buf_t, BPF_ANY);
|
|
|
|
return 0;
|
|
}
|
|
|
|
SEC("uretprobe/SSL_write")
|
|
int probe_ret_SSL_write(struct pt_regs* ctx) {
|
|
u64 current_pid_tgid = bpf_get_current_pid_tgid();
|
|
u32 pid = current_pid_tgid >> 32;
|
|
|
|
#ifndef KERNEL_LESS_5_2
|
|
// if target_ppid is 0 then we target all pids
|
|
if (target_pid != 0 && target_pid != pid) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
// debug_bpf_printk("openssl uretprobe/SSL_write pid :%d\n", pid);
|
|
struct active_ssl_buf* active_ssl_buf_t =
|
|
bpf_map_lookup_elem(&active_ssl_write_args_map, ¤t_pid_tgid);
|
|
if (active_ssl_buf_t != NULL) {
|
|
const char* buf;
|
|
u32 fd = active_ssl_buf_t->fd;
|
|
bpf_probe_read(&buf, sizeof(const char*), &active_ssl_buf_t->buf);
|
|
process_SSL_data(ctx, current_pid_tgid, kSSLWrite, buf, fd);
|
|
}
|
|
bpf_map_delete_elem(&active_ssl_write_args_map, ¤t_pid_tgid);
|
|
return 0;
|
|
}
|
|
|
|
// Function signature being probed:
|
|
// int SSL_read(SSL *s, void *buf, int num)
|
|
SEC("uprobe/SSL_read")
|
|
int probe_entry_SSL_read(struct pt_regs* ctx) {
|
|
u64 current_pid_tgid = bpf_get_current_pid_tgid();
|
|
u32 pid = current_pid_tgid >> 32;
|
|
|
|
#ifndef KERNEL_LESS_5_2
|
|
// if target_ppid is 0 then we target all pids
|
|
if (target_pid != 0 && target_pid != pid) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void* ssl = (void*)PT_REGS_PARM1(ctx);
|
|
// https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/bio/bio_local.h
|
|
struct ssl_st ssl_info;
|
|
bpf_probe_read_user(&ssl_info, sizeof(ssl_info), ssl);
|
|
|
|
struct BIO bio_r;
|
|
bpf_probe_read_user(&bio_r, sizeof(bio_r), ssl_info.rbio);
|
|
|
|
// get fd ssl->rbio->num
|
|
u32 fd = bio_r.num;
|
|
debug_bpf_printk("openssl uprobe PID:%d, SSL_read FD:%d\n", pid, fd);
|
|
|
|
const char* buf = (const char*)PT_REGS_PARM2(ctx);
|
|
struct active_ssl_buf active_ssl_buf_t;
|
|
__builtin_memset(&active_ssl_buf_t, 0, sizeof(active_ssl_buf_t));
|
|
active_ssl_buf_t.fd = fd;
|
|
active_ssl_buf_t.buf = buf;
|
|
bpf_map_update_elem(&active_ssl_read_args_map, ¤t_pid_tgid,
|
|
&active_ssl_buf_t, BPF_ANY);
|
|
return 0;
|
|
}
|
|
|
|
SEC("uretprobe/SSL_read")
|
|
int probe_ret_SSL_read(struct pt_regs* ctx) {
|
|
u64 current_pid_tgid = bpf_get_current_pid_tgid();
|
|
u32 pid = current_pid_tgid >> 32;
|
|
|
|
#ifndef KERNEL_LESS_5_2
|
|
// if target_ppid is 0 then we target all pids
|
|
if (target_pid != 0 && target_pid != pid) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
struct active_ssl_buf* active_ssl_buf_t =
|
|
bpf_map_lookup_elem(&active_ssl_read_args_map, ¤t_pid_tgid);
|
|
if (active_ssl_buf_t != NULL) {
|
|
const char* buf;
|
|
u32 fd = active_ssl_buf_t->fd;
|
|
bpf_probe_read(&buf, sizeof(const char*), &active_ssl_buf_t->buf);
|
|
process_SSL_data(ctx, current_pid_tgid, kSSLRead, buf, fd);
|
|
}
|
|
bpf_map_delete_elem(&active_ssl_read_args_map, ¤t_pid_tgid);
|
|
return 0;
|
|
} |