diff --git a/tap/passive_tapper.go b/tap/passive_tapper.go index e9ecf5216..161b976b4 100644 --- a/tap/passive_tapper.go +++ b/tap/passive_tapper.go @@ -259,9 +259,10 @@ func startPassiveTapper(streamsMap *tcpStreamMap, assembler *tcpAssembler) { func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChannelItem, options *api.TrafficFilteringOptions) *tlstapper.TlsTapper { tls := tlstapper.TlsTapper{} - tlsPerfBufferSize := os.Getpagesize() * 100 + chunksBufferSize := os.Getpagesize() * 100 + logBufferSize := os.Getpagesize() - if err := tls.Init(tlsPerfBufferSize, *procfs, extension); err != nil { + if err := tls.Init(chunksBufferSize, logBufferSize, *procfs, extension); err != nil { tlstapper.LogError(err) return nil } @@ -285,6 +286,7 @@ func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChanne OutputChannel: outputItems, } + go tls.PollForLogging() go tls.Poll(emitter, options) return &tls diff --git a/tap/tlstapper/bpf/fd_to_address_tracepoints.c b/tap/tlstapper/bpf/fd_to_address_tracepoints.c index 12effa18d..d00dfc1a2 100644 --- a/tap/tlstapper/bpf/fd_to_address_tracepoints.c +++ b/tap/tlstapper/bpf/fd_to_address_tracepoints.c @@ -7,8 +7,12 @@ Copyright (C) UP9 Inc. #include "include/headers.h" #include "include/util.h" #include "include/maps.h" +#include "include/log.h" +#include "include/logger_messages.h" #include "include/pids.h" +#define IPV4_ADDR_LEN (16) + struct accept_info { __u64* sockaddr; __u32* addrlen; @@ -41,9 +45,7 @@ void sys_enter_accept4(struct sys_enter_accept4_ctx *ctx) { long err = bpf_map_update_elem(&accept_syscall_context, &id, &info, BPF_ANY); if (err != 0) { - char msg[] = "Error putting accept info (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); - return; + log_error(ctx, LOG_ERROR_PUTTING_ACCEPT_INFO, id, err, 0l); } } @@ -70,6 +72,7 @@ void sys_exit_accept4(struct sys_exit_accept4_ctx *ctx) { struct accept_info *infoPtr = bpf_map_lookup_elem(&accept_syscall_context, &id); if (infoPtr == NULL) { + log_error(ctx, LOG_ERROR_GETTING_ACCEPT_INFO, id, 0l, 0l); return; } @@ -79,15 +82,14 @@ void sys_exit_accept4(struct sys_exit_accept4_ctx *ctx) { bpf_map_delete_elem(&accept_syscall_context, &id); if (err != 0) { - char msg[] = "Error reading accept info from accept syscall (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_READING_ACCEPT_INFO, id, err, 0l); return; } __u32 addrlen; bpf_probe_read(&addrlen, sizeof(__u32), info.addrlen); - if (addrlen != 16) { + if (addrlen != IPV4_ADDR_LEN) { // Currently only ipv4 is supported linux-src/include/linux/inet.h return; } @@ -105,9 +107,7 @@ void sys_exit_accept4(struct sys_exit_accept4_ctx *ctx) { err = bpf_map_update_elem(&file_descriptor_to_ipv4, &key, &fdinfo, BPF_ANY); if (err != 0) { - char msg[] = "Error putting fd to address mapping from accept (key: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), key, err); - return; + log_error(ctx, LOG_ERROR_PUTTING_FD_MAPPING, id, err, ORIGIN_SYS_EXIT_ACCEPT4_CODE); } } @@ -145,9 +145,7 @@ void sys_enter_connect(struct sys_enter_connect_ctx *ctx) { long err = bpf_map_update_elem(&connect_syscall_info, &id, &info, BPF_ANY); if (err != 0) { - char msg[] = "Error putting connect info (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); - return; + log_error(ctx, LOG_ERROR_PUTTING_CONNECT_INFO, id, err, 0l); } } @@ -176,6 +174,7 @@ void sys_exit_connect(struct sys_exit_connect_ctx *ctx) { struct connect_info *infoPtr = bpf_map_lookup_elem(&connect_syscall_info, &id); if (infoPtr == NULL) { + log_error(ctx, LOG_ERROR_GETTING_CONNECT_INFO, id, 0l, 0l); return; } @@ -185,12 +184,11 @@ void sys_exit_connect(struct sys_exit_connect_ctx *ctx) { bpf_map_delete_elem(&connect_syscall_info, &id); if (err != 0) { - char msg[] = "Error reading connect info from connect syscall (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_READING_CONNECT_INFO, id, err, 0l); return; } - if (info.addrlen != 16) { + if (info.addrlen != IPV4_ADDR_LEN) { // Currently only ipv4 is supported linux-src/include/linux/inet.h return; } @@ -208,8 +206,6 @@ void sys_exit_connect(struct sys_exit_connect_ctx *ctx) { err = bpf_map_update_elem(&file_descriptor_to_ipv4, &key, &fdinfo, BPF_ANY); if (err != 0) { - char msg[] = "Error putting fd to address mapping from connect (key: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), key, err); - return; + log_error(ctx, LOG_ERROR_PUTTING_FD_MAPPING, id, err, ORIGIN_SYS_EXIT_CONNECT_CODE); } } diff --git a/tap/tlstapper/bpf/fd_tracepoints.c b/tap/tlstapper/bpf/fd_tracepoints.c index 345d258f3..88add7f44 100644 --- a/tap/tlstapper/bpf/fd_tracepoints.c +++ b/tap/tlstapper/bpf/fd_tracepoints.c @@ -7,6 +7,8 @@ Copyright (C) UP9 Inc. #include "include/headers.h" #include "include/util.h" #include "include/maps.h" +#include "include/log.h" +#include "include/logger_messages.h" #include "include/pids.h" struct sys_enter_read_ctx { @@ -36,8 +38,7 @@ void sys_enter_read(struct sys_enter_read_ctx *ctx) { long err = bpf_probe_read(&info, sizeof(struct ssl_info), infoPtr); if (err != 0) { - char msg[] = "Error reading read info from read syscall (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_READING_SSL_CONTEXT, id, err, ORIGIN_SYS_ENTER_READ_CODE); return; } @@ -46,9 +47,7 @@ void sys_enter_read(struct sys_enter_read_ctx *ctx) { err = bpf_map_update_elem(&ssl_read_context, &id, &info, BPF_ANY); if (err != 0) { - char msg[] = "Error putting file descriptor from read syscall (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); - return; + log_error(ctx, LOG_ERROR_PUTTING_FILE_DESCRIPTOR, id, err, ORIGIN_SYS_ENTER_READ_CODE); } } @@ -79,8 +78,7 @@ void sys_enter_write(struct sys_enter_write_ctx *ctx) { long err = bpf_probe_read(&info, sizeof(struct ssl_info), infoPtr); if (err != 0) { - char msg[] = "Error reading write context from write syscall (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_READING_SSL_CONTEXT, id, err, ORIGIN_SYS_ENTER_WRITE_CODE); return; } @@ -89,8 +87,6 @@ void sys_enter_write(struct sys_enter_write_ctx *ctx) { err = bpf_map_update_elem(&ssl_write_context, &id, &info, BPF_ANY); if (err != 0) { - char msg[] = "Error putting file descriptor from write syscall (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); - return; + log_error(ctx, LOG_ERROR_PUTTING_FILE_DESCRIPTOR, id, err, ORIGIN_SYS_ENTER_WRITE_CODE); } } diff --git a/tap/tlstapper/bpf/include/log.h b/tap/tlstapper/bpf/include/log.h new file mode 100644 index 000000000..9d501024e --- /dev/null +++ b/tap/tlstapper/bpf/include/log.h @@ -0,0 +1,79 @@ +/* +Note: This file is licenced differently from the rest of the project +SPDX-License-Identifier: GPL-2.0 +Copyright (C) UP9 Inc. +*/ + +#ifndef __LOG__ +#define __LOG__ + +// The same consts defined in bpf_logger.go +// +#define LOG_LEVEL_ERROR (0) +#define LOG_LEVEL_INFO (1) +#define LOG_LEVEL_DEBUG (2) + +// The same struct can be found in bpf_logger.go +// +// Be careful when editing, alignment and padding should be exactly the same in go/c. +// +struct log_message { + __u32 level; + __u32 message_code; + __u64 arg1; + __u64 arg2; + __u64 arg3; +}; + +static __always_inline void log_error(void* ctx, __u16 message_code, __u64 arg1, __u64 arg2, __u64 arg3) { + struct log_message entry = {}; + + entry.level = LOG_LEVEL_ERROR; + entry.message_code = message_code; + entry.arg1 = arg1; + entry.arg2 = arg2; + entry.arg3 = arg3; + + long err = bpf_perf_event_output(ctx, &log_buffer, BPF_F_CURRENT_CPU, &entry, sizeof(struct log_message)); + + if (err != 0) { + char msg[] = "Error writing log error to perf buffer - %ld"; + bpf_trace_printk(msg, sizeof(msg), err); + } +} + +static __always_inline void log_info(void* ctx, __u16 message_code, __u64 arg1, __u64 arg2, __u64 arg3) { + struct log_message entry = {}; + + entry.level = LOG_LEVEL_INFO; + entry.message_code = message_code; + entry.arg1 = arg1; + entry.arg2 = arg2; + entry.arg3 = arg3; + + long err = bpf_perf_event_output(ctx, &log_buffer, BPF_F_CURRENT_CPU, &entry, sizeof(struct log_message)); + + if (err != 0) { + char msg[] = "Error writing log info to perf buffer - %ld"; + bpf_trace_printk(msg, sizeof(msg), arg1, err); + } +} + +static __always_inline void log_debug(void* ctx, __u16 message_code, __u64 arg1, __u64 arg2, __u64 arg3) { + struct log_message entry = {}; + + entry.level = LOG_LEVEL_DEBUG; + entry.message_code = message_code; + entry.arg1 = arg1; + entry.arg2 = arg2; + entry.arg3 = arg3; + + long err = bpf_perf_event_output(ctx, &log_buffer, BPF_F_CURRENT_CPU, &entry, sizeof(struct log_message)); + + if (err != 0) { + char msg[] = "Error writing log debug to perf buffer - %ld"; + bpf_trace_printk(msg, sizeof(msg), arg1, err); + } +} + +#endif /* __LOG__ */ diff --git a/tap/tlstapper/bpf/include/logger_messages.h b/tap/tlstapper/bpf/include/logger_messages.h new file mode 100644 index 000000000..69954f43a --- /dev/null +++ b/tap/tlstapper/bpf/include/logger_messages.h @@ -0,0 +1,42 @@ +/* +Note: This file is licenced differently from the rest of the project +SPDX-License-Identifier: GPL-2.0 +Copyright (C) UP9 Inc. +*/ + +#ifndef __LOG_MESSAGES__ +#define __LOG_MESSAGES__ + +// Must be synced with bpf_logger_messages.go +// +#define LOG_ERROR_READING_BYTES_COUNT (0) +#define LOG_ERROR_READING_FD_ADDRESS (1) +#define LOG_ERROR_READING_FROM_SSL_BUFFER (2) +#define LOG_ERROR_BUFFER_TOO_BIG (3) +#define LOG_ERROR_ALLOCATING_CHUNK (4) +#define LOG_ERROR_READING_SSL_CONTEXT (5) +#define LOG_ERROR_PUTTING_SSL_CONTEXT (6) +#define LOG_ERROR_GETTING_SSL_CONTEXT (7) +#define LOG_ERROR_MISSING_FILE_DESCRIPTOR (8) +#define LOG_ERROR_PUTTING_FILE_DESCRIPTOR (9) +#define LOG_ERROR_PUTTING_ACCEPT_INFO (10) +#define LOG_ERROR_GETTING_ACCEPT_INFO (11) +#define LOG_ERROR_READING_ACCEPT_INFO (12) +#define LOG_ERROR_PUTTING_FD_MAPPING (13) +#define LOG_ERROR_PUTTING_CONNECT_INFO (14) +#define LOG_ERROR_GETTING_CONNECT_INFO (15) +#define LOG_ERROR_READING_CONNECT_INFO (16) + +// Sometimes we have the same error, happening from different locations. +// in order to be able to distinct between them in the log, we add an +// extra number that identify the location. The number can be anything, +// but do not give the same number to different origins. +// +#define ORIGIN_SSL_UPROBE_CODE (0l) +#define ORIGIN_SSL_URETPROBE_CODE (1l) +#define ORIGIN_SYS_ENTER_READ_CODE (2l) +#define ORIGIN_SYS_ENTER_WRITE_CODE (3l) +#define ORIGIN_SYS_EXIT_ACCEPT4_CODE (4l) +#define ORIGIN_SYS_EXIT_CONNECT_CODE (5l) + +#endif /* __LOG_MESSAGES__ */ diff --git a/tap/tlstapper/bpf/include/maps.h b/tap/tlstapper/bpf/include/maps.h index 1110f5ca0..dad1ca59d 100644 --- a/tap/tlstapper/bpf/include/maps.h +++ b/tap/tlstapper/bpf/include/maps.h @@ -70,5 +70,6 @@ BPF_LRU_HASH(ssl_write_context, __u64, struct ssl_info); BPF_LRU_HASH(ssl_read_context, __u64, struct ssl_info); BPF_HASH(file_descriptor_to_ipv4, __u64, struct fd_info); BPF_PERF_OUTPUT(chunks_buffer); +BPF_PERF_OUTPUT(log_buffer); #endif /* __MAPS__ */ diff --git a/tap/tlstapper/bpf/openssl_uprobes.c b/tap/tlstapper/bpf/openssl_uprobes.c index e449dd114..a80107511 100644 --- a/tap/tlstapper/bpf/openssl_uprobes.c +++ b/tap/tlstapper/bpf/openssl_uprobes.c @@ -7,6 +7,8 @@ Copyright (C) UP9 Inc. #include "include/headers.h" #include "include/util.h" #include "include/maps.h" +#include "include/log.h" +#include "include/logger_messages.h" #include "include/pids.h" // Heap-like area for eBPF programs - stack size limited to 512 bytes, we must use maps for bigger (chunk) objects. @@ -39,15 +41,14 @@ static __always_inline int get_count_bytes(struct pt_regs *ctx, struct ssl_info* long err = bpf_probe_read(&countBytes, sizeof(size_t), (void*) info->count_ptr); if (err != 0) { - char msg[] = "Error reading bytes count of _ex (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_READING_BYTES_COUNT, id, err, 0l); return 0; } return countBytes; } -static __always_inline void add_address_to_chunk(struct tlsChunk* chunk, __u64 id, __u32 fd) { +static __always_inline void add_address_to_chunk(struct pt_regs *ctx, struct tlsChunk* chunk, __u64 id, __u32 fd) { __u32 pid = id >> 32; __u64 key = (__u64) pid << 32 | fd; @@ -61,8 +62,7 @@ static __always_inline void add_address_to_chunk(struct tlsChunk* chunk, __u64 i chunk->flags |= (fdinfo->flags & FLAGS_IS_CLIENT_BIT); if (err != 0) { - char msg[] = "Error reading from fd address %ld - %ld"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_READING_FD_ADDRESS, id, err, 0l); } } @@ -88,8 +88,7 @@ static __always_inline void send_chunk_part(struct pt_regs *ctx, __u8* buffer, _ } if (err != 0) { - char msg[] = "Error reading from ssl buffer %ld - %ld"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_READING_FROM_SSL_BUFFER, id, err, 0l); return; } @@ -101,8 +100,9 @@ static __always_inline void send_chunk(struct pt_regs *ctx, __u8* buffer, __u64 // // https://lwn.net/Articles/794934/ // - // If we want to compile in kernel older than 5.3, we should add "#pragma unroll" to this loop + // However we want to run in kernel older than 5.3, hence we use "#pragma unroll" anyway // + #pragma unroll for (int i = 0; i < MAX_CHUNKS_PER_OPERATION; i++) { if (chunk->len <= (CHUNK_SIZE * i)) { break; @@ -120,8 +120,7 @@ static __always_inline void output_ssl_chunk(struct pt_regs *ctx, struct ssl_inf } if (countBytes > (CHUNK_SIZE * MAX_CHUNKS_PER_OPERATION)) { - char msg[] = "Buffer too big %d (id: %ld)"; - bpf_trace_printk(msg, sizeof(msg), countBytes, id); + log_error(ctx, LOG_ERROR_BUFFER_TOO_BIG, id, countBytes, 0l); return; } @@ -134,8 +133,7 @@ static __always_inline void output_ssl_chunk(struct pt_regs *ctx, struct ssl_inf chunk = bpf_map_lookup_elem(&heap, &zero); if (!chunk) { - char msg[] = "Unable to allocate chunk (id: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id); + log_error(ctx, LOG_ERROR_ALLOCATING_CHUNK, id, 0l, 0l); return; } @@ -145,11 +143,11 @@ static __always_inline void output_ssl_chunk(struct pt_regs *ctx, struct ssl_inf chunk->len = countBytes; chunk->fd = info->fd; - add_address_to_chunk(chunk, id, chunk->fd); + add_address_to_chunk(ctx, chunk, id, chunk->fd); send_chunk(ctx, info->buffer, id, chunk); } -static __always_inline void ssl_uprobe(void* ssl, void* buffer, int num, struct bpf_map_def* map_fd, size_t *count_ptr) { +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) { __u64 id = bpf_get_current_pid_tgid(); if (!should_tap(id >> 32)) { @@ -166,8 +164,7 @@ static __always_inline void ssl_uprobe(void* ssl, void* buffer, int num, struct long err = bpf_probe_read(&info, sizeof(struct ssl_info), infoPtr); if (err != 0) { - char msg[] = "Error reading old ssl context (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_READING_SSL_CONTEXT, id, err, ORIGIN_SSL_UPROBE_CODE); } if ((bpf_ktime_get_ns() - info.created_at_nano) > SSL_INFO_MAX_TTL_NANO) { @@ -184,8 +181,7 @@ static __always_inline void ssl_uprobe(void* ssl, void* buffer, int num, struct long err = bpf_map_update_elem(map_fd, &id, &info, BPF_ANY); if (err != 0) { - char msg[] = "Error putting ssl context (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_PUTTING_SSL_CONTEXT, id, err, 0l); } } @@ -199,8 +195,7 @@ static __always_inline void ssl_uretprobe(struct pt_regs *ctx, struct bpf_map_de struct ssl_info *infoPtr = bpf_map_lookup_elem(map_fd, &id); if (infoPtr == NULL) { - char msg[] = "Error getting ssl context info (id: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id); + log_error(ctx, LOG_ERROR_GETTING_SSL_CONTEXT, id, 0l, 0l); return; } @@ -220,14 +215,12 @@ static __always_inline void ssl_uretprobe(struct pt_regs *ctx, struct bpf_map_de // bpf_map_delete_elem(map_fd, &id); if (err != 0) { - char msg[] = "Error reading ssl context (id: %ld) (err: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id, err); + log_error(ctx, LOG_ERROR_READING_SSL_CONTEXT, id, err, ORIGIN_SSL_URETPROBE_CODE); return; } if (info.fd == -1) { - char msg[] = "File descriptor is missing from ssl info (id: %ld)"; - bpf_trace_printk(msg, sizeof(msg), id); + log_error(ctx, LOG_ERROR_MISSING_FILE_DESCRIPTOR, id, 0l, 0l); return; } @@ -236,7 +229,7 @@ static __always_inline void ssl_uretprobe(struct pt_regs *ctx, struct bpf_map_de SEC("uprobe/ssl_write") void BPF_KPROBE(ssl_write, void* ssl, void* buffer, int num) { - ssl_uprobe(ssl, buffer, num, &ssl_write_context, 0); + ssl_uprobe(ctx, ssl, buffer, num, &ssl_write_context, 0); } SEC("uretprobe/ssl_write") @@ -246,7 +239,7 @@ void BPF_KPROBE(ssl_ret_write) { SEC("uprobe/ssl_read") void BPF_KPROBE(ssl_read, void* ssl, void* buffer, int num) { - ssl_uprobe(ssl, buffer, num, &ssl_read_context, 0); + ssl_uprobe(ctx, ssl, buffer, num, &ssl_read_context, 0); } SEC("uretprobe/ssl_read") @@ -256,7 +249,7 @@ void BPF_KPROBE(ssl_ret_read) { SEC("uprobe/ssl_write_ex") void BPF_KPROBE(ssl_write_ex, void* ssl, void* buffer, size_t num, size_t *written) { - ssl_uprobe(ssl, buffer, num, &ssl_write_context, written); + ssl_uprobe(ctx, ssl, buffer, num, &ssl_write_context, written); } SEC("uretprobe/ssl_write_ex") @@ -266,7 +259,7 @@ void BPF_KPROBE(ssl_ret_write_ex) { SEC("uprobe/ssl_read_ex") void BPF_KPROBE(ssl_read_ex, void* ssl, void* buffer, size_t num, size_t *readbytes) { - ssl_uprobe(ssl, buffer, num, &ssl_read_context, readbytes); + ssl_uprobe(ctx, ssl, buffer, num, &ssl_read_context, readbytes); } SEC("uretprobe/ssl_read_ex") diff --git a/tap/tlstapper/bpf/tls_tapper.c b/tap/tlstapper/bpf/tls_tapper.c index f48fec6fb..9878ef690 100644 --- a/tap/tlstapper/bpf/tls_tapper.c +++ b/tap/tlstapper/bpf/tls_tapper.c @@ -7,6 +7,8 @@ Copyright (C) UP9 Inc. #include "include/headers.h" #include "include/util.h" #include "include/maps.h" +#include "include/log.h" +#include "include/logger_messages.h" #include "include/pids.h" // To avoid multiple .o files diff --git a/tap/tlstapper/bpf_logger.go b/tap/tlstapper/bpf_logger.go new file mode 100644 index 000000000..ec794e66f --- /dev/null +++ b/tap/tlstapper/bpf_logger.go @@ -0,0 +1,116 @@ +package tlstapper + +import ( + "bytes" + "encoding/binary" + "strings" + + "github.com/cilium/ebpf/perf" + "github.com/go-errors/errors" + "github.com/up9inc/mizu/shared/logger" +) + +const logPrefix = "[bpf] " + +// The same consts defined in log.h +// +const logLevelError = 0 +const logLevelInfo = 1 +const logLevelDebug = 2 + +type logMessage struct { + Level uint32 + MessageCode uint32 + Arg1 uint64 + Arg2 uint64 + Arg3 uint64 +} + +type bpfLogger struct { + logReader *perf.Reader +} + +func newBpfLogger() *bpfLogger { + return &bpfLogger{ + logReader: nil, + } +} + +func (p *bpfLogger) init(bpfObjects *tlsTapperObjects, bufferSize int) error { + var err error + + p.logReader, err = perf.NewReader(bpfObjects.LogBuffer, bufferSize) + + if err != nil { + return errors.Wrap(err, 0) + } + + return nil +} + +func (p *bpfLogger) close() error { + return p.logReader.Close() +} + +func (p *bpfLogger) poll() { + logger.Log.Infof("Start polling for bpf logs") + + for { + record, err := p.logReader.Read() + + if err != nil { + if errors.Is(err, perf.ErrClosed) { + return + } + + LogError(errors.Errorf("Error reading from bpf logger perf buffer, aboring logger! %w", err)) + return + } + + if record.LostSamples != 0 { + logger.Log.Infof("Log buffer is full, dropped %d logs", record.LostSamples) + continue + } + + buffer := bytes.NewReader(record.RawSample) + + var log logMessage + + if err := binary.Read(buffer, binary.LittleEndian, &log); err != nil { + LogError(errors.Errorf("Error parsing log %v", err)) + continue + } + + p.log(&log) + } +} + +func (p *bpfLogger) log(log *logMessage) { + if int(log.MessageCode) >= len(bpfLogMessages) { + logger.Log.Errorf("Unknown message code from bpf logger %d", log.MessageCode) + return + } + + format := bpfLogMessages[log.MessageCode] + tokensCount := strings.Count(format, "%") + + if tokensCount == 0 { + p.logLevel(log.Level, format) + } else if tokensCount == 1 { + p.logLevel(log.Level, format, log.Arg1) + } else if tokensCount == 2 { + p.logLevel(log.Level, format, log.Arg1, log.Arg2) + } else if tokensCount == 3 { + p.logLevel(log.Level, format, log.Arg1, log.Arg2, log.Arg3) + } +} + +func (p *bpfLogger) logLevel(level uint32, format string, args ...interface{}) { + if level == logLevelError { + logger.Log.Errorf(logPrefix+format, args...) + } else if level == logLevelInfo { + logger.Log.Infof(logPrefix+format, args...) + } else if level == logLevelDebug { + logger.Log.Debugf(logPrefix+format, args...) + } +} diff --git a/tap/tlstapper/bpf_logger_messages.go b/tap/tlstapper/bpf_logger_messages.go new file mode 100644 index 000000000..bfcf84138 --- /dev/null +++ b/tap/tlstapper/bpf_logger_messages.go @@ -0,0 +1,25 @@ +package tlstapper + +// Must be synced with logger_messages.h +// +var bpfLogMessages = []string { + /*0000*/ "[%d] Unable to read bytes count from _ex methods [err: %d]", + /*0001*/ "[%d] Unable to read ipv4 address [err: %d]", + /*0002*/ "[%d] Unable to read ssl buffer [err: %d]", + /*0003*/ "[%d] Buffer is too big [size: %d]", + /*0004*/ "[%d] Unable to allocate chunk in bpf heap", + /*0005*/ "[%d] Unable to read ssl context [err: %d] [origin: %d]", + /*0006*/ "[%d] Unable to put ssl context [err: %d]", + /*0007*/ "[%d] Unable to get ssl context", + /*0008*/ "[%d] File descriptor is missing for tls chunk", + /*0009*/ "[%d] Unable to put file descriptor [err: %d] [origin: %d]", + /*0010*/ "[%d] Unable to put accept info [err: %d]", + /*0011*/ "[%d] Unable to get accept info", + /*0012*/ "[%d] Unable to read accept info [err: %d]", + /*0013*/ "[%d] Unable to put file descriptor to address mapping [err: %d] [origin: %d]", + /*0014*/ "[%d] Unable to put connect info [err: %d]", + /*0015*/ "[%d] Unable to get connect info", + /*0016*/ "[%d] Unable to read connect info [err: %d]", + +} + diff --git a/tap/tlstapper/tls_tapper.go b/tap/tlstapper/tls_tapper.go index 6886e147c..e3982bd66 100644 --- a/tap/tlstapper/tls_tapper.go +++ b/tap/tlstapper/tls_tapper.go @@ -8,6 +8,8 @@ import ( "sync" ) +const GLOABL_TAP_PID = 0 + //go:generate go run github.com/cilium/ebpf/cmd/bpf2go tlsTapper bpf/tls_tapper.c -- -O2 -g -D__TARGET_ARCH_x86 type TlsTapper struct { @@ -15,11 +17,12 @@ type TlsTapper struct { syscallHooks syscallHooks sslHooksStructs []sslHooks poller *tlsPoller + bpfLogger *bpfLogger registeredPids sync.Map } -func (t *TlsTapper) Init(bufferSize int, procfs string, extension *api.Extension) error { - logger.Log.Infof("Initializing tls tapper (bufferSize: %v)", bufferSize) +func (t *TlsTapper) Init(chunksBufferSize int, logBufferSize int, procfs string, extension *api.Extension) error { + logger.Log.Infof("Initializing tls tapper (chunksSize: %d) (logSize: %d)", chunksBufferSize, logBufferSize) if err := setupRLimit(); err != nil { return err @@ -37,16 +40,25 @@ func (t *TlsTapper) Init(bufferSize int, procfs string, extension *api.Extension t.sslHooksStructs = make([]sslHooks, 0) + t.bpfLogger = newBpfLogger() + if err := t.bpfLogger.init(&t.bpfObjects, logBufferSize); err != nil { + return err + } + t.poller = newTlsPoller(t, extension, procfs) - return t.poller.init(&t.bpfObjects, bufferSize) + return t.poller.init(&t.bpfObjects, chunksBufferSize) } func (t *TlsTapper) Poll(emitter api.Emitter, options *api.TrafficFilteringOptions) { t.poller.poll(emitter, options) } +func (t *TlsTapper) PollForLogging() { + t.bpfLogger.poll() +} + func (t *TlsTapper) GlobalTap(sslLibrary string) error { - return t.tapPid(0, sslLibrary) + return t.tapPid(GLOABL_TAP_PID, sslLibrary) } func (t *TlsTapper) AddPid(procfs string, pid uint32) error { @@ -74,7 +86,12 @@ func (t *TlsTapper) RemovePid(pid uint32) error { func (t *TlsTapper) ClearPids() { t.registeredPids.Range(func(key, v interface{}) bool { - if err := t.RemovePid(key.(uint32)); err != nil { + pid := key.(uint32) + if pid == GLOABL_TAP_PID { + return true + } + + if err := t.RemovePid(pid); err != nil { LogError(err) } t.registeredPids.Delete(key) @@ -95,6 +112,10 @@ func (t *TlsTapper) Close() []error { errors = append(errors, sslHooks.close()...) } + if err := t.bpfLogger.close(); err != nil { + errors = append(errors, err) + } + if err := t.poller.close(); err != nil { errors = append(errors, err) } diff --git a/tap/tlstapper/tlstapper_bpfeb.go b/tap/tlstapper/tlstapper_bpfeb.go index 03e880b08..a4b07d7f4 100644 --- a/tap/tlstapper/tlstapper_bpfeb.go +++ b/tap/tlstapper/tlstapper_bpfeb.go @@ -78,6 +78,7 @@ type tlsTapperMapSpecs struct { ConnectSyscallInfo *ebpf.MapSpec `ebpf:"connect_syscall_info"` FileDescriptorToIpv4 *ebpf.MapSpec `ebpf:"file_descriptor_to_ipv4"` Heap *ebpf.MapSpec `ebpf:"heap"` + LogBuffer *ebpf.MapSpec `ebpf:"log_buffer"` PidsMap *ebpf.MapSpec `ebpf:"pids_map"` SslReadContext *ebpf.MapSpec `ebpf:"ssl_read_context"` SslWriteContext *ebpf.MapSpec `ebpf:"ssl_write_context"` @@ -107,6 +108,7 @@ type tlsTapperMaps struct { ConnectSyscallInfo *ebpf.Map `ebpf:"connect_syscall_info"` FileDescriptorToIpv4 *ebpf.Map `ebpf:"file_descriptor_to_ipv4"` Heap *ebpf.Map `ebpf:"heap"` + LogBuffer *ebpf.Map `ebpf:"log_buffer"` PidsMap *ebpf.Map `ebpf:"pids_map"` SslReadContext *ebpf.Map `ebpf:"ssl_read_context"` SslWriteContext *ebpf.Map `ebpf:"ssl_write_context"` @@ -119,6 +121,7 @@ func (m *tlsTapperMaps) Close() error { m.ConnectSyscallInfo, m.FileDescriptorToIpv4, m.Heap, + m.LogBuffer, m.PidsMap, m.SslReadContext, m.SslWriteContext, diff --git a/tap/tlstapper/tlstapper_bpfeb.o b/tap/tlstapper/tlstapper_bpfeb.o index 7c62172b0..cbe4c8a1a 100644 Binary files a/tap/tlstapper/tlstapper_bpfeb.o and b/tap/tlstapper/tlstapper_bpfeb.o differ diff --git a/tap/tlstapper/tlstapper_bpfel.go b/tap/tlstapper/tlstapper_bpfel.go index 03c7246a7..eb6ca7281 100644 --- a/tap/tlstapper/tlstapper_bpfel.go +++ b/tap/tlstapper/tlstapper_bpfel.go @@ -78,6 +78,7 @@ type tlsTapperMapSpecs struct { ConnectSyscallInfo *ebpf.MapSpec `ebpf:"connect_syscall_info"` FileDescriptorToIpv4 *ebpf.MapSpec `ebpf:"file_descriptor_to_ipv4"` Heap *ebpf.MapSpec `ebpf:"heap"` + LogBuffer *ebpf.MapSpec `ebpf:"log_buffer"` PidsMap *ebpf.MapSpec `ebpf:"pids_map"` SslReadContext *ebpf.MapSpec `ebpf:"ssl_read_context"` SslWriteContext *ebpf.MapSpec `ebpf:"ssl_write_context"` @@ -107,6 +108,7 @@ type tlsTapperMaps struct { ConnectSyscallInfo *ebpf.Map `ebpf:"connect_syscall_info"` FileDescriptorToIpv4 *ebpf.Map `ebpf:"file_descriptor_to_ipv4"` Heap *ebpf.Map `ebpf:"heap"` + LogBuffer *ebpf.Map `ebpf:"log_buffer"` PidsMap *ebpf.Map `ebpf:"pids_map"` SslReadContext *ebpf.Map `ebpf:"ssl_read_context"` SslWriteContext *ebpf.Map `ebpf:"ssl_write_context"` @@ -119,6 +121,7 @@ func (m *tlsTapperMaps) Close() error { m.ConnectSyscallInfo, m.FileDescriptorToIpv4, m.Heap, + m.LogBuffer, m.PidsMap, m.SslReadContext, m.SslWriteContext, diff --git a/tap/tlstapper/tlstapper_bpfel.o b/tap/tlstapper/tlstapper_bpfel.o index b1686bd39..971f23e8d 100644 Binary files a/tap/tlstapper/tlstapper_bpfel.o and b/tap/tlstapper/tlstapper_bpfel.o differ