From 33445490a0ca9b11beaa75a9ab131e6db7c5e17a Mon Sep 17 00:00:00 2001 From: "sameeh.jubran" Date: Tue, 18 Nov 2025 10:58:40 +0200 Subject: [PATCH 1/2] Add eBPF syscall-write-trace example Includes TCP client/server demo, write() syscall eBPF tracer, Makefile, and full README detailing problem, solution, architecture, and usage. Signed-off-by: sameeh.jubran --- ebpf/README.md | 19 ++ ebpf/syscall-write-trace/.gitignore | 13 + ebpf/syscall-write-trace/Makefile | 51 ++++ ebpf/syscall-write-trace/README.md | 296 ++++++++++++++++++++ ebpf/syscall-write-trace/client-tcp.c | 115 ++++++++ ebpf/syscall-write-trace/server-tcp.c | 150 ++++++++++ ebpf/syscall-write-trace/write_tracer.bpf.c | 97 +++++++ ebpf/syscall-write-trace/write_tracer.c | 180 ++++++++++++ 8 files changed, 921 insertions(+) create mode 100644 ebpf/README.md create mode 100644 ebpf/syscall-write-trace/.gitignore create mode 100755 ebpf/syscall-write-trace/Makefile create mode 100644 ebpf/syscall-write-trace/README.md create mode 100755 ebpf/syscall-write-trace/client-tcp.c create mode 100755 ebpf/syscall-write-trace/server-tcp.c create mode 100755 ebpf/syscall-write-trace/write_tracer.bpf.c create mode 100755 ebpf/syscall-write-trace/write_tracer.c diff --git a/ebpf/README.md b/ebpf/README.md new file mode 100644 index 000000000..6734ae8e1 --- /dev/null +++ b/ebpf/README.md @@ -0,0 +1,19 @@ +## wolfSSL eBPF Examples + +This directory contains **eBPF-based observability examples** demonstrating how Linux eBPF can be used to monitor system calls, user-space wolfSSL operations, network activity, and TLS behavior **without modifying application code**. + +These examples are designed for: + +* **debugging** +* **education** +* **performance tracing** +* **understanding TLS internals** +* **research and experimentation** + +All examples require: + +* Linux kernel with eBPF support (4.19+ recommended) +* clang/LLVM (for compiling `.bpf.c` programs) +* libbpf and libelf +* root privileges +* A recent installation of wolfSSL if running TLS examples \ No newline at end of file diff --git a/ebpf/syscall-write-trace/.gitignore b/ebpf/syscall-write-trace/.gitignore new file mode 100644 index 000000000..e4b9e9d09 --- /dev/null +++ b/ebpf/syscall-write-trace/.gitignore @@ -0,0 +1,13 @@ +# Binaries +client-tcp +server-tcp +write_tracer +*.o +*.bpf.o +*.log + +# Editor files +*~ +*.swp +.DS_Store + diff --git a/ebpf/syscall-write-trace/Makefile b/ebpf/syscall-write-trace/Makefile new file mode 100755 index 000000000..21c70ee45 --- /dev/null +++ b/ebpf/syscall-write-trace/Makefile @@ -0,0 +1,51 @@ +# Makefile for syscall-write-trace example + +CC = gcc +CLANG = clang + +CFLAGS = -O2 -g -Wall +BPF_CFLAGS = -O2 -g -target bpf -D__TARGET_ARCH_$(ARCH) + +# Detect architecture for correct include path +ARCH := $(shell uname -m) +ifeq ($(ARCH),x86_64) + ARCH_DIR = x86_64-linux-gnu +else ifeq ($(ARCH),aarch64) + ARCH_DIR = aarch64-linux-gnu +else + ARCH_DIR = x86_64-linux-gnu +endif + +BPF_INCLUDES = -I/usr/include -I/usr/include/$(ARCH_DIR) +LIBBPF_LIBS = -lbpf -lelf -lz + +TARGETS = write_tracer write_tracer.bpf.o client-tcp server-tcp + +.PHONY: all clean help + +all: $(TARGETS) + +write_tracer.bpf.o: write_tracer.bpf.c + $(CLANG) $(BPF_CFLAGS) $(BPF_INCLUDES) -c $< -o $@ + +write_tracer: write_tracer.c write_tracer.bpf.o + $(CC) $(CFLAGS) write_tracer.c -lelf -lz -lbpf -o write_tracer + +client-tcp: client-tcp.c + $(CC) $(CFLAGS) client-tcp.c -o client-tcp + +server-tcp: server-tcp.c + $(CC) $(CFLAGS) server-tcp.c -o server-tcp + +clean: + rm -f *.o write_tracer client-tcp server-tcp + +help: + @echo "Targets:" + @echo " all - Build syscall tracer and TCP demo apps" + @echo " clean - Remove binaries" + @echo "" + @echo "Instructions:" + @echo " 1. sudo ./write_tracer" + @echo " 2. ./server-tcp" + @echo " 3. ./client-tcp 127.0.0.1" diff --git a/ebpf/syscall-write-trace/README.md b/ebpf/syscall-write-trace/README.md new file mode 100644 index 000000000..c44e95951 --- /dev/null +++ b/ebpf/syscall-write-trace/README.md @@ -0,0 +1,296 @@ +# syscall-write-trace + +### eBPF Example: Tracing Plaintext at the `write()` Syscall Boundary + +This example demonstrates how to use **Linux eBPF** to intercept the `write()` system call and extract plaintext data **before the kernel performs any buffering, encryption, or processing**. +It uses a simple TCP client/server pair to generate predictable network writes and an eBPF tracepoint program to observe them. + +This example is part of the **wolfSSL eBPF observability suite**, designed to help developers understand how plaintext flows through the system and how eBPF can be used to debug, monitor, or study application behavior without modifying application code. + +--- + +# πŸ“Œ **Problem** + +When debugging network applications, especially TLS applications, developers often want to inspect: + +* What plaintext is being written +* What data is being sent to the network +* Whether buffers contain what we expect +* Whether the application or kernel is modifying data +* Whether the problem is at the app layer, kernel layer, or crypto layer + +However, once an application calls: + +``` +write(fd, buffer, count) +``` + +the kernel: + +* does **not** expose the plaintext +* may buffer or coalesce writes +* may encrypt data (TLS offload, QUIC, etc.) +* hides memory from tools +* provides no visibility into the user buffer + +Traditional debugging tools (tcpdump, Wireshark, strace) **cannot see the plaintext** before encryption or kernel processing. + +This creates a visibility gap. + +--- + +# 🎯 **Solution** + +We attach an **eBPF tracepoint** to: + +``` +tracepoint/syscalls/sys_enter_write +``` + +This gives us: + +* access to the syscall arguments +* the calling process’s PID/TID +* the file descriptor +* the byte count +* the raw user pointer to the data +* ability to read the plaintext with `bpf_probe_read_user()` + +The eBPF program: + +1. Filters events only from a target process (`client-tcp`) +2. Copies up to 255 bytes of user-space buffer safely +3. Sends them to user-space via a perf buffer +4. The userspace loader prints ASCII and hex output + +This provides **perfect visibility** into the plaintext leaving the application. + +--- + +# 🧩 **Architecture** + +``` + TCP Client App (user space) + | + | 1. call write(fd, buf, count) + v + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ tracepoint: sys_enter_write β”‚ ← eBPF hook runs BEFORE write executes + β”‚ eBPF program: β”‚ + β”‚ - filters process name β”‚ + β”‚ - reads buffer from user mem β”‚ + β”‚ - emits event via perf buf β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + | + | 2. event (plaintext) + v + Userspace Loader (write_tracer) + -------------------------------- + - loads BPF program + - attaches tracepoint + - opens perf buffer + - prints plaintext + | + | 3. human-readable output + v + Terminal +``` + +--- + +# πŸ” **Detailed Walkthrough** + +## 1. The Sample Applications + +### `server-tcp.c` + +A simple TCP echo server on port 11111: + +* waits for a connection +* receives a message +* prints it +* echoes back a canned response +* loops + +### `client-tcp.c` + +A matching TCP client: + +* prompts user for input +* writes it to the server +* prints server response + +These programs provide **predictable write() calls** for tracing. + +--- + +## 2. The eBPF Program: `write_tracer.bpf.c` + +Hooks: + +``` +tracepoint/syscalls/sys_enter_write +``` + +Key details: + +### βœ” Event Filtering + +Checks the process name (`comm`) to avoid tracing all processes. + +### βœ” Safe Memory Access + +Uses: + +``` +bpf_probe_read_user() +``` + +to copy user memory safely, limited to 255 bytes (verifier-friendly bound). + +### βœ” Perf Buffer Emission + +Writes events to a ring buffer consumed by user-space. + +### βœ” Struct of event data + +Contains: + +* PID, TID +* FD +* count +* process name +* captured data + +--- + +## 3. The Userspace Loader: `write_tracer.c` + +It: + +1. Raises RLIMIT_MEMLOCK +2. Loads `write_tracer.bpf.o` +3. Attaches the tracepoint +4. Opens perf buffer +5. Pretty-prints events: + +``` +=== WRITE SYSCALL INTERCEPTED === +Process: client-tcp (PID: 1234) +FD: 3 +Count: 13 bytes +Data: "hello world!" +Hex: 68 65 6c ... +``` + +This gives full plaintext visibility. + +--- + +# πŸš€ **How to Build** + +Dependencies (Ubuntu): + +```bash +sudo apt install clang llvm libbpf-dev libelf-dev zlib1g-dev build-essential +``` + +Then: + +```bash +make +``` + +This compiles: + +* TCP client/server +* eBPF program (`write_tracer.bpf.o`) +* userspace loader (`write_tracer`) + +--- + +# ▢️ **How to Run** + +### 1. Terminal #1 β€” Start the tracer + +```bash +sudo ./write_tracer +``` + +### 2. Terminal #2 β€” Start the TCP server + +```bash +./server-tcp +``` + +### 3. Terminal #3 β€” Run client and type message + +```bash +./client-tcp 127.0.0.1 +``` + +Tracer output: + +``` +=== WRITE SYSCALL INTERCEPTED === +Process: client-tcp +File Descriptor: 3 +Write Count: 13 bytes +Data (first 13 bytes): hello world! +``` + +--- + +# 🎁 **Benefits of This Example** + +### βœ” Shows how to read plaintext before kernel/network/TLS processing + +### βœ” Demonstrates safe buffer access in eBPF + +### βœ” Demonstrates filtering (PID, process name) + +### βœ” Teaches core eBPF concepts: tracepoints, perf buffers, verifier constraints + +### βœ” Foundation for more advanced examples (TLS plaintext, handshake tracing) + +### βœ” Helps wolfSSL developers debug TLS behavior + +### βœ” Useful for application developers integrating wolfSSL + +--- + +# βš™οΈ **Nitty-Gritty Details** + +### 1. Why tracepoint instead of kprobe? + +Tracepoints are: + +* stable +* argument offsets fixed +* preferred for syscall entry tracing + +Allows verifier to analyze program more easily. + +### 2. Why use process name filtering? + +Without it, the tracer prints: + +* output from bash +* systemd +* everything reading/writing + +Filtering avoids noise. + +### 3. Why limit buffer to 255 bytes? + +Verifier restrictions require fixed bounded copy sizes. +A 255-byte buffer is safe and sufficient for demos. + +### 4. Why use perf buffer instead of ringbuf? + +Perf buffer is more compatible with older kernels (e.g., Ubuntu LTS). +Perfect for examples. + +### 5. Why use simple TCP client/server? + +Consistent, predictable write() calls make tracing easy to demo. diff --git a/ebpf/syscall-write-trace/client-tcp.c b/ebpf/syscall-write-trace/client-tcp.c new file mode 100755 index 000000000..cf53412bf --- /dev/null +++ b/ebpf/syscall-write-trace/client-tcp.c @@ -0,0 +1,115 @@ +/* client-tcp.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* the usual suspects */ +#include +#include +#include + +/* socket includes */ +#include +#include +#include +#include + +#define DEFAULT_PORT 11111 + + + +int main(int argc, char** argv) +{ + int sockfd; + struct sockaddr_in servAddr; + char buff[256]; + size_t len; + int ret; + + + /* Check for proper calling convention */ + if (argc != 2) { + printf("usage: %s \n", argv[0]); + return 0; + } + + /* Create a socket that uses an internet IPv4 address, + * Sets the socket to be stream based (TCP), + * 0 means choose the default protocol. */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "ERROR: failed to create the socket\n"); + ret = -1; + goto end; + } + + /* Initialize the server address struct with zeros */ + memset(&servAddr, 0, sizeof(servAddr)); + + /* Fill in the server address */ + servAddr.sin_family = AF_INET; /* using IPv4 */ + servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */ + + /* Get the server IPv4 address from the command line call */ + if (inet_pton(AF_INET, argv[1], &servAddr.sin_addr) != 1) { + fprintf(stderr, "ERROR: invalid address\n"); + ret = -1; + goto end; + } + + /* Connect to the server */ + if ((ret = connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr))) + == -1) { + fprintf(stderr, "ERROR: failed to connect\n"); + goto end; + } + + /* Get a message for the server from stdin */ + printf("Message for server: "); + memset(buff, 0, sizeof(buff)); + if (fgets(buff, sizeof(buff), stdin) == NULL) { + fprintf(stderr, "ERROR: failed to get message for server\n"); + ret = -1; + goto socket_cleanup; + } + len = strnlen(buff, sizeof(buff)); + + /* Send the message to the server */ + if (write(sockfd, buff, len) != len) { + fprintf(stderr, "ERROR: failed to write\n"); + ret = -1; + goto socket_cleanup; + } + + /* Read the server data into our buff array */ + memset(buff, 0, sizeof(buff)); + if (read(sockfd, buff, sizeof(buff)-1) == -1) { + fprintf(stderr, "ERROR: failed to read\n"); + ret = -1; + goto socket_cleanup; + } + + /* Print to stdout any data the server sends */ + printf("Server: %s\n", buff); + + /* Cleanup and return */ +socket_cleanup: + close(sockfd); /* Close the connection to the server */ +end: + return ret; /* Return reporting a success */ +} diff --git a/ebpf/syscall-write-trace/server-tcp.c b/ebpf/syscall-write-trace/server-tcp.c new file mode 100755 index 000000000..5511175ce --- /dev/null +++ b/ebpf/syscall-write-trace/server-tcp.c @@ -0,0 +1,150 @@ +/* server-tcp.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* the usual suspects */ +#include +#include +#include + +/* socket includes */ +#include +#include +#include +#include + +#define DEFAULT_PORT 11111 + + + +int main() +{ + int ret; + int sockfd; + int connd; + struct sockaddr_in servAddr; + struct sockaddr_in clientAddr; + socklen_t size = sizeof(clientAddr); + char buff[256]; + size_t len; + int shutdown = 0; + const char* reply = "I hear ya fa shizzle!\n"; + + + + /* Create a socket that uses an internet IPv4 address, + * Sets the socket to be stream based (TCP), + * 0 means choose the default protocol. */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "ERROR: failed to create the socket\n"); + ret = -1; + goto end; + } + + + + /* Initialize the server address struct with zeros */ + memset(&servAddr, 0, sizeof(servAddr)); + + /* Fill in the server address */ + servAddr.sin_family = AF_INET; /* using IPv4 */ + servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */ + servAddr.sin_addr.s_addr = INADDR_ANY; /* from anywhere */ + + + + /* Bind the server socket to our port */ + if (bind(sockfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) { + fprintf(stderr, "ERROR: failed to bind\n"); + ret = -1; + goto servsocket_cleanup; + } + + /* Listen for a new connection, allow 5 pending connections */ + if (listen(sockfd, 5) == -1) { + fprintf(stderr, "ERROR: failed to listen\n"); + ret = -1; + goto servsocket_cleanup; + } + + + + /* Continue to accept clients until shutdown is issued */ + while (!shutdown) { + printf("Waiting for a connection...\n"); + + /* Accept client connections */ + if ((connd = accept(sockfd, (struct sockaddr*)&clientAddr, &size)) + == -1) { + fprintf(stderr, "ERROR: failed to accept the connection\n\n"); + ret = -1; + goto servsocket_cleanup; + } + + printf("Client connected successfully\n"); + + + + /* Read the client data into our buff array */ + memset(buff, 0, sizeof(buff)); + if ((ret = read(connd, buff, sizeof(buff)-1)) == -1) { + fprintf(stderr, "ERROR: failed to read\n"); + goto clientsocket_cleanup; + } + + /* Print to stdout any data the client sends */ + printf("Client: %s\n", buff); + + /* Check for server shutdown command */ + if (strncmp(buff, "shutdown", 8) == 0) { + printf("Shutdown command issued!\n"); + shutdown = 1; + } + + + + /* Write our reply into buff */ + memset(buff, 0, sizeof(buff)); + memcpy(buff, reply, strlen(reply)); + len = strnlen(buff, sizeof(buff)); + + /* Reply back to the client */ + if ((ret = write(connd, buff, len)) != len) { + fprintf(stderr, "ERROR: failed to write\n"); + goto clientsocket_cleanup; + } + + + + /* Cleanup after this connection */ + close(connd); /* Close the connection to the client */ + } + + printf("Shutdown complete\n"); + + + /* Cleanup and return */ +clientsocket_cleanup: + close(connd); /* Close the connection to the client */ +servsocket_cleanup: + close(sockfd); /* Close the socket listening for clients */ +end: + return ret; /* Return reporting a success */ +} diff --git a/ebpf/syscall-write-trace/write_tracer.bpf.c b/ebpf/syscall-write-trace/write_tracer.bpf.c new file mode 100755 index 000000000..8112c4bc0 --- /dev/null +++ b/ebpf/syscall-write-trace/write_tracer.bpf.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +char LICENSE[] SEC("license") = "GPL"; + +// Define the tracepoint structure based on kernel BTF +struct trace_entry { + unsigned short type; + unsigned char flags; + unsigned char preempt_count; + int pid; +}; + +struct trace_event_raw_sys_enter { + struct trace_entry ent; + long int id; + long unsigned int args[6]; +}; + +struct write_event { + __u32 pid; + __u32 tid; + int fd; + __u64 count; + char comm[16]; + char data[256]; +}; + +struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); +} events SEC(".maps"); + +// Use syscall tracepoint with BPF_PROG macro for proper argument extraction +SEC("tp/syscalls/sys_enter_write") +int trace_write_enter(struct trace_event_raw_sys_enter *ctx) +{ + struct write_event event = {}; + __u64 pid_tgid; + __u32 pid, tid; + char comm[16]; + long ret; + unsigned int fd; + char *buf; + unsigned long count; + + pid_tgid = bpf_get_current_pid_tgid(); + pid = pid_tgid >> 32; + tid = (__u32)pid_tgid; + + bpf_get_current_comm(&comm, sizeof(comm)); + + // Filter: only trace "client-tcp" process + // Unrolled string comparison for verifier + if (comm[0] != 'c' || comm[1] != 'l' || comm[2] != 'i' || + comm[3] != 'e' || comm[4] != 'n' || comm[5] != 't' || + comm[6] != '-' || comm[7] != 't' || comm[8] != 'c' || comm[9] != 'p') { + return 0; + } + + // The syscall arguments are stored in ctx->args[] + // args[0] = fd, args[1] = buf, args[2] = count + fd = (unsigned int)ctx->args[0]; + buf = (char *)ctx->args[1]; + count = (unsigned long)ctx->args[2]; + + event.pid = pid; + event.tid = tid; + event.fd = fd; + event.count = count; + + bpf_get_current_comm(&event.comm, sizeof(event.comm)); + + // Read user buffer data with bounds checking + if (count > 0 && buf != 0) { + unsigned long len = count; + if (len > 255) { + len = 255; + } + + // Use bpf_probe_read_user to safely read from user space + ret = bpf_probe_read_user(event.data, len, buf); + if (ret < 0) { + event.data[0] = '\0'; + } else if (len < 256) { + event.data[len] = '\0'; + } + } else { + event.data[0] = '\0'; + } + + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + return 0; +} diff --git a/ebpf/syscall-write-trace/write_tracer.c b/ebpf/syscall-write-trace/write_tracer.c new file mode 100755 index 000000000..adb717f7b --- /dev/null +++ b/ebpf/syscall-write-trace/write_tracer.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct write_event { + __u32 pid; + __u32 tid; + int fd; + __u64 count; + char comm[16]; + char data[256]; +}; + +static volatile bool running = true; + +static void sig_handler(int sig) +{ + running = false; +} + +static void handle_event(void *ctx, int cpu, void *data, __u32 data_sz) +{ + struct write_event *e = data; + + printf("=== WRITE SYSCALL INTERCEPTED ===\n"); + printf("Process: %s (PID: %u, TID: %u)\n", e->comm, e->pid, e->tid); + printf("File Descriptor: %d\n", e->fd); + printf("Write Count: %llu bytes\n", e->count); + printf("Data (first %zu bytes): ", strlen(e->data)); + + for (int i = 0; i < strlen(e->data) && i < 64; i++) { + char c = e->data[i]; + if (c >= 32 && c <= 126) { + printf("%c", c); + } else { + printf("\\x%02x", (unsigned char)c); + } + } + printf("\n"); + + printf("Data (hex): "); + for (int i = 0; i < strlen(e->data) && i < 32; i++) { + printf("%02x ", (unsigned char)e->data[i]); + } + printf("\n"); + printf("=====================================\n\n"); +} + +static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) +{ + printf("Lost %llu events on CPU #%d!\n", lost_cnt, cpu); +} + +static int bump_memlock_rlimit(void) +{ + struct rlimit rlim_new = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; + + if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) { + fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit: %s\n", strerror(errno)); + fprintf(stderr, "You may need to run this program with sudo or adjust system limits.\n"); + return -1; + } + return 0; +} + +static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) +{ + /* Only print warnings and errors */ + if (level <= LIBBPF_WARN) + return vfprintf(stderr, format, args); + return 0; +} + +int main(int argc, char **argv) +{ + struct bpf_object *obj; + struct bpf_program *prog; + struct bpf_link *link; + struct perf_buffer *pb; + int map_fd; + int err; + + /* Set up libbpf logging callback */ + libbpf_set_print(libbpf_print_fn); + + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + printf("Loading eBPF program to trace write() syscalls...\n"); + + /* Check if we're running as root */ + if (geteuid() != 0) { + fprintf(stderr, "Error: This program must be run as root (use sudo).\n"); + fprintf(stderr, "Example: sudo %s\n", argv[0]); + return 1; + } + + /* Bump RLIMIT_MEMLOCK to allow BPF map creation */ + if (bump_memlock_rlimit()) { + fprintf(stderr, "Failed to increase rlimit\n"); + return 1; + } + + printf("Press Ctrl+C to stop.\n\n"); + + obj = bpf_object__open_file("write_tracer.bpf.o", NULL); + if (libbpf_get_error(obj)) { + fprintf(stderr, "Failed to open BPF object file\n"); + return 1; + } + + err = bpf_object__load(obj); + if (err) { + fprintf(stderr, "Failed to load BPF object: %d\n", err); + goto cleanup; + } + + prog = bpf_object__find_program_by_name(obj, "trace_write_enter"); + if (!prog) { + fprintf(stderr, "Failed to find BPF program\n"); + err = 1; + goto cleanup; + } + + link = bpf_program__attach(prog); + if (libbpf_get_error(link)) { + fprintf(stderr, "Failed to attach BPF program\n"); + err = 1; + goto cleanup; + } + + map_fd = bpf_object__find_map_fd_by_name(obj, "events"); + if (map_fd < 0) { + fprintf(stderr, "Failed to find events map\n"); + err = 1; + goto cleanup_link; + } + + struct perf_buffer_opts pb_opts = { + .sample_cb = handle_event, + .lost_cb = handle_lost_events, + }; + + pb = perf_buffer__new(map_fd, 8, &pb_opts); + if (libbpf_get_error(pb)) { + fprintf(stderr, "Failed to create perf buffer\n"); + err = 1; + goto cleanup_link; + } + + printf("Successfully loaded and attached eBPF program!\n"); + printf("Monitoring write() syscalls...\n\n"); + + while (running) { + err = perf_buffer__poll(pb, 100); + if (err < 0 && err != -EINTR) { + fprintf(stderr, "Error polling perf buffer: %d\n", err); + break; + } + } + + printf("\nShutting down...\n"); + + perf_buffer__free(pb); +cleanup_link: + bpf_link__destroy(link); +cleanup: + bpf_object__close(obj); + return err; +} From 2079de8cba04aea07aba2a93345a7f15259fd5a7 Mon Sep 17 00:00:00 2001 From: "sameeh.jubran" Date: Wed, 19 Nov 2025 12:11:33 +0200 Subject: [PATCH 2/2] ebpf: add trace wolfSSL_write() and wolfSSL_read() using eBPF uprobes. Includes: - TLS client and server examples - eBPF programs for write/read entry and read return - userspace loader with perf buffer handling - automatic symbol lookup (no hardcoded offsets) - x86_64 and ARM64 register handling - full README with usage, architecture, and explanation Shows how to observe TLS plaintext inside applications without modifying wolfSSL or application code. Signed-off-by: sameeh.jubran --- ebpf/tls-uprobe-trace/.gitignore | 13 + ebpf/tls-uprobe-trace/Makefile | 44 +++ ebpf/tls-uprobe-trace/README.md | 230 ++++++++++++++ ebpf/tls-uprobe-trace/ca-cert.pem | 93 ++++++ ebpf/tls-uprobe-trace/client-tls.c | 187 ++++++++++++ ebpf/tls-uprobe-trace/server-cert.pem | 185 ++++++++++++ ebpf/tls-uprobe-trace/server-key.pem | 27 ++ ebpf/tls-uprobe-trace/server-tls.c | 229 ++++++++++++++ ebpf/tls-uprobe-trace/wolfssl_uprobe.bpf.c | 219 ++++++++++++++ ebpf/tls-uprobe-trace/wolfssl_uprobe.c | 335 +++++++++++++++++++++ 10 files changed, 1562 insertions(+) create mode 100644 ebpf/tls-uprobe-trace/.gitignore create mode 100644 ebpf/tls-uprobe-trace/Makefile create mode 100644 ebpf/tls-uprobe-trace/README.md create mode 100755 ebpf/tls-uprobe-trace/ca-cert.pem create mode 100755 ebpf/tls-uprobe-trace/client-tls.c create mode 100755 ebpf/tls-uprobe-trace/server-cert.pem create mode 100755 ebpf/tls-uprobe-trace/server-key.pem create mode 100755 ebpf/tls-uprobe-trace/server-tls.c create mode 100755 ebpf/tls-uprobe-trace/wolfssl_uprobe.bpf.c create mode 100755 ebpf/tls-uprobe-trace/wolfssl_uprobe.c diff --git a/ebpf/tls-uprobe-trace/.gitignore b/ebpf/tls-uprobe-trace/.gitignore new file mode 100644 index 000000000..dda4a6fcb --- /dev/null +++ b/ebpf/tls-uprobe-trace/.gitignore @@ -0,0 +1,13 @@ +# Binaries +client-tls +server-tls +wolfssl_uprobe +*.o +*.bpf.o +*.log + +# Editor files +*~ +*.swp +.DS_Store + diff --git a/ebpf/tls-uprobe-trace/Makefile b/ebpf/tls-uprobe-trace/Makefile new file mode 100644 index 000000000..3da5a294f --- /dev/null +++ b/ebpf/tls-uprobe-trace/Makefile @@ -0,0 +1,44 @@ +CC = gcc +CLANG = clang +CFLAGS = -O2 -g -Wall + +# Auto-detect host arch, convert to BPF target name +UNAME_M := $(shell uname -m) + +ifeq ($(UNAME_M), x86_64) + BPF_ARCH := x86 + UAPI_PATH := /usr/include/x86_64-linux-gnu +else ifeq ($(UNAME_M), aarch64) + BPF_ARCH := arm64 + UAPI_PATH := /usr/include/aarch64-linux-gnu +else + $(error Unsupported architecture: $(UNAME_M)) +endif + +BPF_CFLAGS = -O2 -g -target bpf -D__TARGET_ARCH_$(BPF_ARCH) + +LIBBPF_LIBS = -lbpf -lelf -lz + +TARGETS = client-tls server-tls wolfssl_uprobe wolfssl_uprobe.bpf.o + +all: $(TARGETS) + +# ===== TLS Programs ===== +client-tls: client-tls.c + $(CC) $(CFLAGS) $< -o $@ -lwolfssl + +server-tls: server-tls.c + $(CC) $(CFLAGS) $< -o $@ -lwolfssl + +# ===== eBPF Program ===== +wolfssl_uprobe.bpf.o: wolfssl_uprobe.bpf.c + $(CLANG) $(BPF_CFLAGS) \ + -I/usr/include \ + -I$(UAPI_PATH) \ + -c $< -o $@ + +wolfssl_uprobe: wolfssl_uprobe.c wolfssl_uprobe.bpf.o + $(CC) $(CFLAGS) $< -o $@ $(LIBBPF_LIBS) + +clean: + rm -f $(TARGETS) *.o *.log diff --git a/ebpf/tls-uprobe-trace/README.md b/ebpf/tls-uprobe-trace/README.md new file mode 100644 index 000000000..f13d3e248 --- /dev/null +++ b/ebpf/tls-uprobe-trace/README.md @@ -0,0 +1,230 @@ +# `tls-uprobe-trace` – Tracing `wolfSSL_write()` and `wolfSSL_read()` with eBPF + +This example demonstrates how to use **eBPF uprobes** to observe **plaintext TLS data** inside applications that use **wolfSSL**. +Because decryption happens *inside the process* (not in the kernel), traditional tools like `tcpdump` or kprobes **cannot see decrypted SSL/TLS plaintext**. +Uprobes make it possible to attach to userspace functions such as `wolfSSL_write()` and `wolfSSL_read()` and extract: + +* plaintext being written (encrypted later by TLS) +* plaintext being read (already decrypted by TLS) +* PID/TID +* SSL* internal pointer +* byte count + sample of the buffer +* process name + +This example includes: + +βœ”οΈ TLS client +βœ”οΈ TLS server +βœ”οΈ eBPF probe attached to `wolfSSL_write` +βœ”οΈ eBPF probe attached to `wolfSSL_read` (uretprobe) +βœ”οΈ Perf buffer event delivery to user space +βœ”οΈ Architecture-portable code (x86_64 & ARM64) +βœ”οΈ Symbol lookup (no hardcoding offsets) + +--- + +## 1. Problem + +When using TLS, all application data is encrypted before it leaves the process: + +``` +cleartext β†’ wolfSSL_write() β†’ encrypt β†’ kernel β†’ network +network β†’ kernel β†’ decrypt β†’ wolfSSL_read() β†’ cleartext +``` + +This means: + +* Kernel tools **cannot see decrypted payloads** +* tcpdump/wireshark **see only ciphertext** +* syscall tracing (e.g., `sys_enter_write`) **sees ciphertext** +* security & observability tools cannot inspect application-level data + +For debugging, auditing, or educational purposes, developers often need a way to inspect: + +* what plaintext the application *actually sent* +* what plaintext it *actually received* + +--- + +## 2. Solution: eBPF Uprobes on wolfSSL + +eBPF uprobes allow attaching to **any userspace function**. +By attaching to: + +* `wolfSSL_write()` β†’ entry probe +* `wolfSSL_read()` β†’ entry + return probes + +we can safely extract plaintext buffers from user-space memory *before encryption* or *after decryption*. + +This example uses: + +* `trace_wolfssl_write_enter` +* `trace_wolfssl_read_enter` +* `trace_wolfssl_read_exit` + +The eBPF program reads arguments from registers (`PT_REGS_PARM1`, etc.), copies user-space buffers via `bpf_probe_read_user()`, and emits structured events to a perf buffer. + +--- + +## 3. Benefits + +### βœ”οΈ Observe decrypted TLS data + +See exactly what `client-tls` and `server-tls` send and receive. + +### βœ”οΈ No modification to wolfSSL or application + +Zero instrumentation changes required. + +### βœ”οΈ Low overhead & safe + +eBPF verifier guarantees memory safety; uprobes only execute on function entry/exit. + +### βœ”οΈ Works with any application using wolfSSL + +Examples reuse standard wolfSSL examples with no changes. + +### βœ”οΈ Foundation for deeper wolfSSL observability + +Future variants can trace: + +* handshake events +* cipher suite negotiation +* session resumption +* key export callbacks +* user-defined I/O callbacks + +--- + +## 4. Architecture + +``` + +---------------------------+ + | TLS Application | + | (client-tls / server-tls)| + +-------------+-------------+ + | TLS API + v + wolfSSL_write() / wolfSSL_read() + | + -------- uprobe / uretprobe --------- + | + eBPF programs (BPF bytecode) + | + perf event ring buffer + | + userspace loader (wolfssl_uprobe) + | + human-readable terminal output +``` + +### Files included: + +| File | Purpose | +| ----------------------------------- | -------------------------------------------- | +| `client-tls.c` | TLS client using wolfSSL | +| `server-tls.c` | TLS server using wolfSSL | +| `wolfssl_uprobe.c` | eBPF loader + perf buffer consumer | +| `wolfssl_uprobe.bpf.c` | eBPF program (uprobes on wolfSSL_write/read) | +| `Makefile` | Build everything cleanly for x86 or ARM | +| `server-cert.pem`, `server-key.pem` | Minimal test certs | + +--- + +## 5. Building + +### Requirements + +```bash +sudo apt install clang llvm libbpf-dev libelf-dev zlib1g-dev make +``` + +wolfSSL must be installed (shared library): + +```bash +sudo make install +sudo ldconfig +``` + +### Build everything + +```bash +make +``` + +This produces: + +* `client-tls` +* `server-tls` +* `wolfssl_uprobe` +* `wolfssl_uprobe.bpf.o` + +--- + +## 6. Running the Example + +### 1. Start the eBPF tracer + +(must run as root) + +```bash +sudo ./wolfssl_uprobe +``` + +You should see: + +``` +Successfully loaded and attached eBPF programs! +Monitoring wolfSSL_write() and wolfSSL_read() calls... +``` + +### 2. Start the TLS server + +```bash +./server-tls +``` + +### 3. Start the TLS client + +```bash +./client-tls 127.0.0.1 +Message for server: hello world! +``` + +### Expected tracer output + +#### From `wolfSSL_write`: + +``` +=== wolfSSL_write() INTERCEPTED === +Process: client-tls (PID: 2312) +Write Count: 12 bytes +Data: hello world! +===================================== +``` + +#### From `wolfSSL_read`: + +``` +=== wolfSSL_read() INTERCEPTED === +Process: client-tls (PID: 2312) +Bytes Read: 25 +Decrypted Data: I hear ya fa shizzle! +===================================== +``` + +--- + +## 7. Notes & Limitations + +* Tracing is implemented using **uprobes**, so only plaintext inside userspace is visible (by design). +* The example currently filters to process name `client-tls` to reduce noise. +* Return probe (`uretprobe`) only fires once TLS read returns to user space. + +--- + +## 8. Cleanup + +```bash +make clean +``` \ No newline at end of file diff --git a/ebpf/tls-uprobe-trace/ca-cert.pem b/ebpf/tls-uprobe-trace/ca-cert.pem new file mode 100755 index 000000000..bb4abe7bc --- /dev/null +++ b/ebpf/tls-uprobe-trace/ca-cert.pem @@ -0,0 +1,93 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 6b:9b:70:c6:f1:a3:94:65:19:a1:08:58:ef:a7:8d:2b:7a:83:c1:da + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Validity + Not Before: Dec 18 21:25:29 2024 GMT + Not After : Sep 14 21:25:29 2027 GMT + Subject: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:0c:ca:2d:14:b2:1e:84:42:5b:cd:38:1f:4a: + f2:4d:75:10:f1:b6:35:9f:df:ca:7d:03:98:d3:ac: + de:03:66:ee:2a:f1:d8:b0:7d:6e:07:54:0b:10:98: + 21:4d:80:cb:12:20:e7:cc:4f:de:45:7d:c9:72:77: + 32:ea:ca:90:bb:69:52:10:03:2f:a8:f3:95:c5:f1: + 8b:62:56:1b:ef:67:6f:a4:10:41:95:ad:0a:9b:e3: + a5:c0:b0:d2:70:76:50:30:5b:a8:e8:08:2c:7c:ed: + a7:a2:7a:8d:38:29:1c:ac:c7:ed:f2:7c:95:b0:95: + 82:7d:49:5c:38:cd:77:25:ef:bd:80:75:53:94:3c: + 3d:ca:63:5b:9f:15:b5:d3:1d:13:2f:19:d1:3c:db: + 76:3a:cc:b8:7d:c9:e5:c2:d7:da:40:6f:d8:21:dc: + 73:1b:42:2d:53:9c:fe:1a:fc:7d:ab:7a:36:3f:98: + de:84:7c:05:67:ce:6a:14:38:87:a9:f1:8c:b5:68: + cb:68:7f:71:20:2b:f5:a0:63:f5:56:2f:a3:26:d2: + b7:6f:b1:5a:17:d7:38:99:08:fe:93:58:6f:fe:c3: + 13:49:08:16:0b:a7:4d:67:00:52:31:67:23:4e:98: + ed:51:45:1d:b9:04:d9:0b:ec:d8:28:b3:4b:bd:ed: + 36:79 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5 + X509v3 Authority Key Identifier: + keyid:27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5 + DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=info@wolfssl.com + serial:6B:9B:70:C6:F1:A3:94:65:19:A1:08:58:EF:A7:8D:2B:7A:83:C1:DA + X509v3 Basic Constraints: + CA:TRUE + X509v3 Subject Alternative Name: + DNS:example.com, IP Address:127.0.0.1 + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 77:3b:3d:66:74:bc:97:fe:40:16:e6:ba:a5:d5:d1:84:08:89: + 69:4f:88:0d:57:a9:ef:8c:c3:97:52:c8:bd:8b:a2:49:3b:b7: + f7:5d:1e:d6:14:7f:b2:80:33:da:a0:8a:d3:e1:2f:d5:bc:33: + 9f:ea:5a:72:24:e5:f8:b8:4b:b3:df:62:90:3b:a8:21:ef:27: + 42:75:bc:60:02:8e:37:35:99:eb:a3:28:f2:65:4c:ff:7a:f8: + 8e:cc:23:6d:e5:6a:fe:22:5a:d9:b2:4f:47:c7:e0:ae:98:ef: + 94:ac:b6:4f:61:81:29:8e:e1:79:2c:46:fc:e9:1a:c3:96:1f: + 19:93:64:2e:9f:37:72:c5:e4:93:4e:61:5f:38:8e:ae:e8:39: + 19:e6:97:a8:91:d4:23:7e:1e:d2:d0:53:ec:cc:ac:a0:1d:d0: + b7:dd:b1:b7:01:2e:96:cd:85:27:e0:e7:47:e2:c1:c1:00:f6: + 94:df:77:e7:fa:c6:ef:8a:c0:7c:67:bc:ff:a0:7c:94:3b:7d: + 86:42:af:3d:83:31:ee:2a:3b:7b:f0:2c:9e:6f:e9:c4:07:81: + 24:da:05:70:4d:dd:09:ae:9e:72:b8:21:0e:8c:b2:ab:aa:4c: + 49:10:f7:76:f9:b5:0d:6c:20:d3:df:7a:06:32:8d:29:1f:28: + 1d:8d:26:33 +-----BEGIN CERTIFICATE----- +MIIE/zCCA+egAwIBAgIUa5twxvGjlGUZoQhY76eNK3qDwdowDQYJKoZIhvcNAQEL +BQAwgZQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdC +b3plbWFuMREwDwYDVQQKDAhTYXd0b290aDETMBEGA1UECwwKQ29uc3VsdGluZzEY +MBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdv +bGZzc2wuY29tMB4XDTI0MTIxODIxMjUyOVoXDTI3MDkxNDIxMjUyOVowgZQxCzAJ +BgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMREw +DwYDVQQKDAhTYXd0b290aDETMBEGA1UECwwKQ29uc3VsdGluZzEYMBYGA1UEAwwP +d3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29t +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvwzKLRSyHoRCW804H0ry +TXUQ8bY1n9/KfQOY06zeA2buKvHYsH1uB1QLEJghTYDLEiDnzE/eRX3Jcncy6sqQ +u2lSEAMvqPOVxfGLYlYb72dvpBBBla0Km+OlwLDScHZQMFuo6AgsfO2nonqNOCkc +rMft8nyVsJWCfUlcOM13Je+9gHVTlDw9ymNbnxW10x0TLxnRPNt2Osy4fcnlwtfa +QG/YIdxzG0ItU5z+Gvx9q3o2P5jehHwFZ85qFDiHqfGMtWjLaH9xICv1oGP1Vi+j +JtK3b7FaF9c4mQj+k1hv/sMTSQgWC6dNZwBSMWcjTpjtUUUduQTZC+zYKLNLve02 +eQIDAQABo4IBRTCCAUEwHQYDVR0OBBYEFCeOZxF0wyYdP+0zY7Ok2B0w5ejVMIHU +BgNVHSMEgcwwgcmAFCeOZxF0wyYdP+0zY7Ok2B0w5ejVoYGapIGXMIGUMQswCQYD +VQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjERMA8G +A1UECgwIU2F3dG9vdGgxEzARBgNVBAsMCkNvbnN1bHRpbmcxGDAWBgNVBAMMD3d3 +dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbYIU +a5twxvGjlGUZoQhY76eNK3qDwdowDAYDVR0TBAUwAwEB/zAcBgNVHREEFTATggtl +eGFtcGxlLmNvbYcEfwAAATAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +DQYJKoZIhvcNAQELBQADggEBAHc7PWZ0vJf+QBbmuqXV0YQIiWlPiA1Xqe+Mw5dS +yL2Lokk7t/ddHtYUf7KAM9qgitPhL9W8M5/qWnIk5fi4S7PfYpA7qCHvJ0J1vGAC +jjc1meujKPJlTP96+I7MI23lav4iWtmyT0fH4K6Y75Sstk9hgSmO4XksRvzpGsOW +HxmTZC6fN3LF5JNOYV84jq7oORnml6iR1CN+HtLQU+zMrKAd0LfdsbcBLpbNhSfg +50fiwcEA9pTfd+f6xu+KwHxnvP+gfJQ7fYZCrz2DMe4qO3vwLJ5v6cQHgSTaBXBN +3QmunnK4IQ6MsquqTEkQ93b5tQ1sINPfegYyjSkfKB2NJjM= +-----END CERTIFICATE----- diff --git a/ebpf/tls-uprobe-trace/client-tls.c b/ebpf/tls-uprobe-trace/client-tls.c new file mode 100755 index 000000000..1dfe720c0 --- /dev/null +++ b/ebpf/tls-uprobe-trace/client-tls.c @@ -0,0 +1,187 @@ +/* client-tls.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* the usual suspects */ +#include +#include +#include + +/* socket includes */ +#include +#include +#include +#include + +/* wolfSSL */ +#include +#include + +#define DEFAULT_PORT 11111 + +#define CERT_FILE "./ca-cert.pem" + + + +int main(int argc, char** argv) +{ + int sockfd; + struct sockaddr_in servAddr; + char buff[256]; + size_t len; + int ret; + + /* declare wolfSSL objects */ + WOLFSSL_CTX* ctx; + WOLFSSL* ssl; + + + + /* Check for proper calling convention */ + if (argc != 2) { + printf("usage: %s \n", argv[0]); + return 0; + } + + /* Create a socket that uses an internet IPv4 address, + * Sets the socket to be stream based (TCP), + * 0 means choose the default protocol. */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "ERROR: failed to create the socket\n"); + ret = -1; + goto end; + } + + /* Initialize the server address struct with zeros */ + memset(&servAddr, 0, sizeof(servAddr)); + + /* Fill in the server address */ + servAddr.sin_family = AF_INET; /* using IPv4 */ + servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */ + + /* Get the server IPv4 address from the command line call */ + if (inet_pton(AF_INET, argv[1], &servAddr.sin_addr) != 1) { + fprintf(stderr, "ERROR: invalid address\n"); + ret = -1; + goto end; + } + + /* Connect to the server */ + if ((ret = connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr))) + == -1) { + fprintf(stderr, "ERROR: failed to connect\n"); + goto end; + } + + /*---------------------------------*/ + /* Start of wolfSSL initialization and configuration */ + /*---------------------------------*/ + /* Initialize wolfSSL */ + if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: Failed to initialize the library\n"); + goto socket_cleanup; + } + + /* Create and initialize WOLFSSL_CTX */ +#ifdef USE_TLSV13 + ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); +#else + ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()); +#endif + if (ctx == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n"); + ret = -1; + goto socket_cleanup; + } + + /* Load client certificates into WOLFSSL_CTX */ + if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CERT_FILE, NULL)) + != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", + CERT_FILE); + goto ctx_cleanup; + } + + /* Create a WOLFSSL object */ + if ((ssl = wolfSSL_new(ctx)) == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL object\n"); + ret = -1; + goto ctx_cleanup; + } + + /* Attach wolfSSL to the socket */ + if ((ret = wolfSSL_set_fd(ssl, sockfd)) != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: Failed to set the file descriptor\n"); + goto cleanup; + } + + /* Connect to wolfSSL on the server side */ + if ((ret = wolfSSL_connect(ssl)) != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to connect to wolfSSL\n"); + goto cleanup; + } + + /* Get a message for the server from stdin */ + printf("Message for server: "); + memset(buff, 0, sizeof(buff)); + if (fgets(buff, sizeof(buff), stdin) == NULL) { + fprintf(stderr, "ERROR: failed to get message for server\n"); + ret = -1; + goto cleanup; + } + len = strnlen(buff, sizeof(buff)); + + /* Send the message to the server */ + if ((ret = wolfSSL_write(ssl, buff, len)) != len) { + fprintf(stderr, "ERROR: failed to write entire message\n"); + fprintf(stderr, "%d bytes of %d bytes were sent", ret, (int) len); + goto cleanup; + } + + /* Read the server data into our buff array */ + memset(buff, 0, sizeof(buff)); + if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) == -1) { + fprintf(stderr, "ERROR: failed to read\n"); + goto cleanup; + } + + /* Print to stdout any data the server sends */ + printf("Server: %s\n", buff); + + /* Bidirectional shutdown */ + while (wolfSSL_shutdown(ssl) == WOLFSSL_SHUTDOWN_NOT_DONE) { + printf("Shutdown not complete\n"); + } + + printf("Shutdown complete\n"); + + ret = 0; + + /* Cleanup and return */ +cleanup: + wolfSSL_free(ssl); /* Free the wolfSSL object */ +ctx_cleanup: + wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */ + wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */ +socket_cleanup: + close(sockfd); /* Close the connection to the server */ +end: + return ret; /* Return reporting a success */ +} diff --git a/ebpf/tls-uprobe-trace/server-cert.pem b/ebpf/tls-uprobe-trace/server-cert.pem new file mode 100755 index 000000000..6fc3db772 --- /dev/null +++ b/ebpf/tls-uprobe-trace/server-cert.pem @@ -0,0 +1,185 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Validity + Not Before: Dec 18 21:25:30 2024 GMT + Not After : Sep 14 21:25:30 2027 GMT + Subject: C = US, ST = Montana, L = Bozeman, O = wolfSSL, OU = Support, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c0:95:08:e1:57:41:f2:71:6d:b7:d2:45:41:27: + 01:65:c6:45:ae:f2:bc:24:30:b8:95:ce:2f:4e:d6: + f6:1c:88:bc:7c:9f:fb:a8:67:7f:fe:5c:9c:51:75: + f7:8a:ca:07:e7:35:2f:8f:e1:bd:7b:c0:2f:7c:ab: + 64:a8:17:fc:ca:5d:7b:ba:e0:21:e5:72:2e:6f:2e: + 86:d8:95:73:da:ac:1b:53:b9:5f:3f:d7:19:0d:25: + 4f:e1:63:63:51:8b:0b:64:3f:ad:43:b8:a5:1c:5c: + 34:b3:ae:00:a0:63:c5:f6:7f:0b:59:68:78:73:a6: + 8c:18:a9:02:6d:af:c3:19:01:2e:b8:10:e3:c6:cc: + 40:b4:69:a3:46:33:69:87:6e:c4:bb:17:a6:f3:e8: + dd:ad:73:bc:7b:2f:21:b5:fd:66:51:0c:bd:54:b3: + e1:6d:5f:1c:bc:23:73:d1:09:03:89:14:d2:10:b9: + 64:c3:2a:d0:a1:96:4a:bc:e1:d4:1a:5b:c7:a0:c0: + c1:63:78:0f:44:37:30:32:96:80:32:23:95:a1:77: + ba:13:d2:97:73:e2:5d:25:c9:6a:0d:c3:39:60:a4: + b4:b0:69:42:42:09:e9:d8:08:bc:33:20:b3:58:22: + a7:aa:eb:c4:e1:e6:61:83:c5:d2:96:df:d9:d0:4f: + ad:d7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + B3:11:32:C9:92:98:84:E2:C9:F8:D0:3B:6E:03:42:CA:1F:0E:8E:3C + X509v3 Authority Key Identifier: + keyid:27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5 + DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=info@wolfssl.com + serial:6B:9B:70:C6:F1:A3:94:65:19:A1:08:58:EF:A7:8D:2B:7A:83:C1:DA + X509v3 Basic Constraints: + CA:TRUE + X509v3 Subject Alternative Name: + DNS:example.com, IP Address:127.0.0.1 + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 8a:f1:4e:e8:9f:59:b2:d9:13:ac:fc:42:c4:81:34:9f:6b:39: + 57:9c:e9:92:5d:41:ac:05:35:b1:26:93:4d:4a:da:f8:51:82: + d2:8d:7f:d3:5c:6e:29:80:8d:9b:02:10:2b:64:f5:d1:31:06: + fa:85:2b:8f:63:32:14:76:7a:39:15:f3:4e:dd:fd:e2:2c:90: + 15:d1:6f:73:87:ee:e6:c8:eb:ad:40:d5:e8:94:1f:a6:7e:26: + 5b:87:ba:0f:06:5a:4d:55:7a:aa:c4:09:34:8b:f7:e5:cc:d6: + b7:6c:46:6d:a1:e6:66:66:4c:4b:e5:12:31:37:54:49:64:a5: + 66:eb:e0:c6:a1:49:f8:4d:c3:d3:55:a4:05:d2:ac:fb:e1:c8: + 69:30:4b:98:fd:72:1a:ab:9f:86:eb:0d:bd:7c:a6:3d:81:d9: + 01:a7:8a:79:ab:3c:ce:e5:b6:c3:1b:ef:7d:5e:37:7b:37:7c: + 91:89:59:11:21:11:7c:05:80:e1:a8:d6:f9:35:da:1b:86:06: + 5a:32:67:6c:a9:2b:e0:31:7b:89:53:37:42:af:34:a4:53:d2: + 7c:91:50:63:3a:8e:4a:1f:a3:90:4e:7c:41:59:1d:eb:7b:a2: + 14:87:ba:76:36:a4:77:46:34:f2:55:50:f0:24:9f:83:83:da: + a6:aa:3c:c8 +-----BEGIN CERTIFICATE----- +MIIE6DCCA9CgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNh +d3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz +bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjQxMjE4 +MjEyNTMwWhcNMjcwOTE0MjEyNTMwWjCBkDELMAkGA1UEBhMCVVMxEDAOBgNVBAgM +B01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xEDAOBgNVBAoMB3dvbGZTU0wxEDAO +BgNVBAsMB1N1cHBvcnQxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG +SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMCVCOFXQfJxbbfSRUEnAWXGRa7yvCQwuJXOL07W9hyIvHyf+6hn +f/5cnFF194rKB+c1L4/hvXvAL3yrZKgX/Mpde7rgIeVyLm8uhtiVc9qsG1O5Xz/X +GQ0lT+FjY1GLC2Q/rUO4pRxcNLOuAKBjxfZ/C1loeHOmjBipAm2vwxkBLrgQ48bM +QLRpo0YzaYduxLsXpvPo3a1zvHsvIbX9ZlEMvVSz4W1fHLwjc9EJA4kU0hC5ZMMq +0KGWSrzh1Bpbx6DAwWN4D0Q3MDKWgDIjlaF3uhPSl3PiXSXJag3DOWCktLBpQkIJ +6dgIvDMgs1gip6rrxOHmYYPF0pbf2dBPrdcCAwEAAaOCAUUwggFBMB0GA1UdDgQW +BBSzETLJkpiE4sn40DtuA0LKHw6OPDCB1AYDVR0jBIHMMIHJgBQnjmcRdMMmHT/t +M2OzpNgdMOXo1aGBmqSBlzCBlDELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01vbnRh +bmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNhd3Rvb3RoMRMwEQYDVQQL +DApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG +9w0BCQEWEGluZm9Ad29sZnNzbC5jb22CFGubcMbxo5RlGaEIWO+njSt6g8HaMAwG +A1UdEwQFMAMBAf8wHAYDVR0RBBUwE4ILZXhhbXBsZS5jb22HBH8AAAEwHQYDVR0l +BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCK8U7o +n1my2ROs/ELEgTSfazlXnOmSXUGsBTWxJpNNStr4UYLSjX/TXG4pgI2bAhArZPXR +MQb6hSuPYzIUdno5FfNO3f3iLJAV0W9zh+7myOutQNXolB+mfiZbh7oPBlpNVXqq +xAk0i/flzNa3bEZtoeZmZkxL5RIxN1RJZKVm6+DGoUn4TcPTVaQF0qz74chpMEuY +/XIaq5+G6w29fKY9gdkBp4p5qzzO5bbDG+99Xjd7N3yRiVkRIRF8BYDhqNb5Ndob +hgZaMmdsqSvgMXuJUzdCrzSkU9J8kVBjOo5KH6OQTnxBWR3re6IUh7p2NqR3RjTy +VVDwJJ+Dg9qmqjzI +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 6b:9b:70:c6:f1:a3:94:65:19:a1:08:58:ef:a7:8d:2b:7a:83:c1:da + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Validity + Not Before: Dec 18 21:25:29 2024 GMT + Not After : Sep 14 21:25:29 2027 GMT + Subject: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:0c:ca:2d:14:b2:1e:84:42:5b:cd:38:1f:4a: + f2:4d:75:10:f1:b6:35:9f:df:ca:7d:03:98:d3:ac: + de:03:66:ee:2a:f1:d8:b0:7d:6e:07:54:0b:10:98: + 21:4d:80:cb:12:20:e7:cc:4f:de:45:7d:c9:72:77: + 32:ea:ca:90:bb:69:52:10:03:2f:a8:f3:95:c5:f1: + 8b:62:56:1b:ef:67:6f:a4:10:41:95:ad:0a:9b:e3: + a5:c0:b0:d2:70:76:50:30:5b:a8:e8:08:2c:7c:ed: + a7:a2:7a:8d:38:29:1c:ac:c7:ed:f2:7c:95:b0:95: + 82:7d:49:5c:38:cd:77:25:ef:bd:80:75:53:94:3c: + 3d:ca:63:5b:9f:15:b5:d3:1d:13:2f:19:d1:3c:db: + 76:3a:cc:b8:7d:c9:e5:c2:d7:da:40:6f:d8:21:dc: + 73:1b:42:2d:53:9c:fe:1a:fc:7d:ab:7a:36:3f:98: + de:84:7c:05:67:ce:6a:14:38:87:a9:f1:8c:b5:68: + cb:68:7f:71:20:2b:f5:a0:63:f5:56:2f:a3:26:d2: + b7:6f:b1:5a:17:d7:38:99:08:fe:93:58:6f:fe:c3: + 13:49:08:16:0b:a7:4d:67:00:52:31:67:23:4e:98: + ed:51:45:1d:b9:04:d9:0b:ec:d8:28:b3:4b:bd:ed: + 36:79 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5 + X509v3 Authority Key Identifier: + keyid:27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5 + DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=info@wolfssl.com + serial:6B:9B:70:C6:F1:A3:94:65:19:A1:08:58:EF:A7:8D:2B:7A:83:C1:DA + X509v3 Basic Constraints: + CA:TRUE + X509v3 Subject Alternative Name: + DNS:example.com, IP Address:127.0.0.1 + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 77:3b:3d:66:74:bc:97:fe:40:16:e6:ba:a5:d5:d1:84:08:89: + 69:4f:88:0d:57:a9:ef:8c:c3:97:52:c8:bd:8b:a2:49:3b:b7: + f7:5d:1e:d6:14:7f:b2:80:33:da:a0:8a:d3:e1:2f:d5:bc:33: + 9f:ea:5a:72:24:e5:f8:b8:4b:b3:df:62:90:3b:a8:21:ef:27: + 42:75:bc:60:02:8e:37:35:99:eb:a3:28:f2:65:4c:ff:7a:f8: + 8e:cc:23:6d:e5:6a:fe:22:5a:d9:b2:4f:47:c7:e0:ae:98:ef: + 94:ac:b6:4f:61:81:29:8e:e1:79:2c:46:fc:e9:1a:c3:96:1f: + 19:93:64:2e:9f:37:72:c5:e4:93:4e:61:5f:38:8e:ae:e8:39: + 19:e6:97:a8:91:d4:23:7e:1e:d2:d0:53:ec:cc:ac:a0:1d:d0: + b7:dd:b1:b7:01:2e:96:cd:85:27:e0:e7:47:e2:c1:c1:00:f6: + 94:df:77:e7:fa:c6:ef:8a:c0:7c:67:bc:ff:a0:7c:94:3b:7d: + 86:42:af:3d:83:31:ee:2a:3b:7b:f0:2c:9e:6f:e9:c4:07:81: + 24:da:05:70:4d:dd:09:ae:9e:72:b8:21:0e:8c:b2:ab:aa:4c: + 49:10:f7:76:f9:b5:0d:6c:20:d3:df:7a:06:32:8d:29:1f:28: + 1d:8d:26:33 +-----BEGIN CERTIFICATE----- +MIIE/zCCA+egAwIBAgIUa5twxvGjlGUZoQhY76eNK3qDwdowDQYJKoZIhvcNAQEL +BQAwgZQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdC +b3plbWFuMREwDwYDVQQKDAhTYXd0b290aDETMBEGA1UECwwKQ29uc3VsdGluZzEY +MBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdv +bGZzc2wuY29tMB4XDTI0MTIxODIxMjUyOVoXDTI3MDkxNDIxMjUyOVowgZQxCzAJ +BgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMREw +DwYDVQQKDAhTYXd0b290aDETMBEGA1UECwwKQ29uc3VsdGluZzEYMBYGA1UEAwwP +d3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29t +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvwzKLRSyHoRCW804H0ry +TXUQ8bY1n9/KfQOY06zeA2buKvHYsH1uB1QLEJghTYDLEiDnzE/eRX3Jcncy6sqQ +u2lSEAMvqPOVxfGLYlYb72dvpBBBla0Km+OlwLDScHZQMFuo6AgsfO2nonqNOCkc +rMft8nyVsJWCfUlcOM13Je+9gHVTlDw9ymNbnxW10x0TLxnRPNt2Osy4fcnlwtfa +QG/YIdxzG0ItU5z+Gvx9q3o2P5jehHwFZ85qFDiHqfGMtWjLaH9xICv1oGP1Vi+j +JtK3b7FaF9c4mQj+k1hv/sMTSQgWC6dNZwBSMWcjTpjtUUUduQTZC+zYKLNLve02 +eQIDAQABo4IBRTCCAUEwHQYDVR0OBBYEFCeOZxF0wyYdP+0zY7Ok2B0w5ejVMIHU +BgNVHSMEgcwwgcmAFCeOZxF0wyYdP+0zY7Ok2B0w5ejVoYGapIGXMIGUMQswCQYD +VQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjERMA8G +A1UECgwIU2F3dG9vdGgxEzARBgNVBAsMCkNvbnN1bHRpbmcxGDAWBgNVBAMMD3d3 +dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbYIU +a5twxvGjlGUZoQhY76eNK3qDwdowDAYDVR0TBAUwAwEB/zAcBgNVHREEFTATggtl +eGFtcGxlLmNvbYcEfwAAATAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +DQYJKoZIhvcNAQELBQADggEBAHc7PWZ0vJf+QBbmuqXV0YQIiWlPiA1Xqe+Mw5dS +yL2Lokk7t/ddHtYUf7KAM9qgitPhL9W8M5/qWnIk5fi4S7PfYpA7qCHvJ0J1vGAC +jjc1meujKPJlTP96+I7MI23lav4iWtmyT0fH4K6Y75Sstk9hgSmO4XksRvzpGsOW +HxmTZC6fN3LF5JNOYV84jq7oORnml6iR1CN+HtLQU+zMrKAd0LfdsbcBLpbNhSfg +50fiwcEA9pTfd+f6xu+KwHxnvP+gfJQ7fYZCrz2DMe4qO3vwLJ5v6cQHgSTaBXBN +3QmunnK4IQ6MsquqTEkQ93b5tQ1sINPfegYyjSkfKB2NJjM= +-----END CERTIFICATE----- diff --git a/ebpf/tls-uprobe-trace/server-key.pem b/ebpf/tls-uprobe-trace/server-key.pem new file mode 100755 index 000000000..d1627f4d4 --- /dev/null +++ b/ebpf/tls-uprobe-trace/server-key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAwJUI4VdB8nFtt9JFQScBZcZFrvK8JDC4lc4vTtb2HIi8fJ/7 +qGd//lycUXX3isoH5zUvj+G9e8AvfKtkqBf8yl17uuAh5XIuby6G2JVz2qwbU7lf +P9cZDSVP4WNjUYsLZD+tQ7ilHFw0s64AoGPF9n8LWWh4c6aMGKkCba/DGQEuuBDj +xsxAtGmjRjNph27Euxem8+jdrXO8ey8htf1mUQy9VLPhbV8cvCNz0QkDiRTSELlk +wyrQoZZKvOHUGlvHoMDBY3gPRDcwMpaAMiOVoXe6E9KXc+JdJclqDcM5YKS0sGlC +Qgnp2Ai8MyCzWCKnquvE4eZhg8XSlt/Z0E+t1wIDAQABAoIBAQCa0DQPUmIFUAHv +n+1kbsLE2hryhNeSEEiSxOlq64t1bMZ5OPLJckqGZFSVd8vDmp231B2kAMieTuTd +x7pnFsF0vKnWlI8rMBr77d8hBSPZSjm9mGtlmrjcxH3upkMVLj2+HSJgKnMw1T7Y +oqyGQy7E9WReP4l1DxHYUSVOn9iqo85gs+KK2X4b8GTKmlsFC1uqy+XjP24yIgXz +0PrvdFKB4l90073/MYNFdfpjepcu1rYZxpIm5CgGUFAOeC6peA0Ul7QS2DFAq6EB +QcIw+AdfFuRhd9Jg8p+N6PS662PeKpeB70xs5lU0USsoNPRTHMRYCj+7r7X3SoVD +LTzxWFiBAoGBAPIsVHY5I2PJEDK3k62vvhl1loFk5rW4iUJB0W3QHBv4G6xpyzY8 +ZH3c9Bm4w2CxV0hfUk9ZOlV/MsAZQ1A/rs5vF/MOn0DKTq0VO8l56cBZOHNwnAp8 +yTpIMqfYSXUKhcLC/RVz2pkJKmmanwpxv7AEpox6Wm9IWlQ7xrFTF9/nAoGBAMuT +3ncVXbdcXHzYkKmYLdZpDmOzo9ymzItqpKISjI57SCyySzfcBhh96v52odSh6T8N +zRtfr1+elltbD6F8r7ObkNtXczrtsCNErkFPHwdCEyNMy/r0FKTV9542fFufqDzB +hV900jkt/9CE3/uzIHoumxeu5roLrl9TpFLtG8SRAoGBAOyY2rvV/vlSSn0CVUlv +VW5SL4SjK7OGYrNU0mNS2uOIdqDvixWl0xgUcndex6MEH54ZYrUbG57D8rUy+UzB +qusMJn3UX0pRXKRFBnBEp1bA1CIUdp7YY1CJkNPiv4GVkjFBhzkaQwsYpVMfORpf +H0O8h2rfbtMiAP4imHBOGhkpAoGBAIpBVihRnl/Ungs7mKNU8mxW1KrpaTOFJAza +1AwtxL9PAmk4fNTm3Ezt1xYRwz4A58MmwFEC3rt1nG9WnHrzju/PisUr0toGakTJ +c/5umYf4W77xfOZltU9s8MnF/xbKixsX4lg9ojerAby/QM5TjI7t7+5ZneBj5nxe +9Y5L8TvBAoGATUX5QIzFW/QqGoq08hysa+kMVja3TnKW1eWK0uL/8fEYEz2GCbjY +dqfJHHFSlDBD4PF4dP1hG0wJzOZoKnGtHN9DvFbbpaS+NXCkXs9P/ABVmTo9I89n +WvUi+LUp0EQR6zUuRr79jhiyX6i/GTKh9dwD5nyaHwx8qbAOITc78bA= +-----END RSA PRIVATE KEY----- diff --git a/ebpf/tls-uprobe-trace/server-tls.c b/ebpf/tls-uprobe-trace/server-tls.c new file mode 100755 index 000000000..fd8ed23ec --- /dev/null +++ b/ebpf/tls-uprobe-trace/server-tls.c @@ -0,0 +1,229 @@ +/* server-tls.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* the usual suspects */ +#include +#include +#include + +/* socket includes */ +#include +#include +#include +#include + +/* wolfSSL */ +#include +#include + +#define DEFAULT_PORT 11111 + +#define CERT_FILE "./server-cert.pem" +#define KEY_FILE "./server-key.pem" + + + +int main() +{ + int sockfd = SOCKET_INVALID; + int connd = SOCKET_INVALID; + struct sockaddr_in servAddr; + struct sockaddr_in clientAddr; + socklen_t size = sizeof(clientAddr); + char buff[256]; + size_t len; + int shutdown = 0; + int ret; + const char* reply = "I hear ya fa shizzle!\n"; + + /* declare wolfSSL objects */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + WOLFSSL_CIPHER* cipher; + +#if 0 + wolfSSL_Debugging_ON(); +#endif + + /* Initialize wolfSSL */ + wolfSSL_Init(); + + + + /* Create a socket that uses an internet IPv4 address, + * Sets the socket to be stream based (TCP), + * 0 means choose the default protocol. */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "ERROR: failed to create the socket\n"); + ret = -1; + goto exit; + } + + + + /* Create and initialize WOLFSSL_CTX */ +#ifdef USE_TLSV13 + ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()); +#else + ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()); +#endif + if (ctx == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n"); + ret = -1; + goto exit; + } + + /* Load server certificates into WOLFSSL_CTX */ + if ((ret = wolfSSL_CTX_use_certificate_file(ctx, CERT_FILE, WOLFSSL_FILETYPE_PEM)) + != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", + CERT_FILE); + goto exit; + } + + /* Load server key into WOLFSSL_CTX */ + if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, WOLFSSL_FILETYPE_PEM)) + != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", + KEY_FILE); + goto exit; + } + + + + /* Initialize the server address struct with zeros */ + memset(&servAddr, 0, sizeof(servAddr)); + + /* Fill in the server address */ + servAddr.sin_family = AF_INET; /* using IPv4 */ + servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */ + servAddr.sin_addr.s_addr = INADDR_ANY; /* from anywhere */ + + + + /* Bind the server socket to our port */ + if (bind(sockfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) { + fprintf(stderr, "ERROR: failed to bind\n"); + ret = -1; + goto exit; + } + + /* Listen for a new connection, allow 5 pending connections */ + if (listen(sockfd, 5) == -1) { + fprintf(stderr, "ERROR: failed to listen\n"); + ret = -1; + goto exit; + } + + + + /* Continue to accept clients until shutdown is issued */ + while (!shutdown) { + printf("Waiting for a connection...\n"); + + /* Accept client connections */ + if ((connd = accept(sockfd, (struct sockaddr*)&clientAddr, &size)) + == -1) { + fprintf(stderr, "ERROR: failed to accept the connection\n\n"); + ret = -1; + goto exit; + } + + /* Create a WOLFSSL object */ + if ((ssl = wolfSSL_new(ctx)) == NULL) { + fprintf(stderr, "ERROR: failed to create WOLFSSL object\n"); + ret = -1; + goto exit; + } + + /* Attach wolfSSL to the socket */ + wolfSSL_set_fd(ssl, connd); + + /* Establish TLS connection */ + ret = wolfSSL_accept(ssl); + if (ret != WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_accept error = %d\n", + wolfSSL_get_error(ssl, ret)); + goto exit; + } + + + printf("Client connected successfully\n"); + + cipher = wolfSSL_get_current_cipher(ssl); + printf("SSL cipher suite is %s\n", wolfSSL_CIPHER_get_name(cipher)); + + + /* Read the client data into our buff array */ + memset(buff, 0, sizeof(buff)); + if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) == -1) { + fprintf(stderr, "ERROR: failed to read\n"); + goto exit; + } + + /* Print to stdout any data the client sends */ + printf("Client: %s\n", buff); + + /* Check for server shutdown command */ + if (strncmp(buff, "shutdown", 8) == 0) { + printf("Shutdown command issued!\n"); + shutdown = 1; + } + + + + /* Write our reply into buff */ + memset(buff, 0, sizeof(buff)); + memcpy(buff, reply, strlen(reply)); + len = strnlen(buff, sizeof(buff)); + + /* Reply back to the client */ + if ((ret = wolfSSL_write(ssl, buff, len)) != len) { + fprintf(stderr, "ERROR: failed to write\n"); + goto exit; + } + + /* Notify the client that the connection is ending */ + wolfSSL_shutdown(ssl); + printf("Shutdown complete\n"); + + /* Cleanup after this connection */ + wolfSSL_free(ssl); /* Free the wolfSSL object */ + ssl = NULL; + close(connd); /* Close the connection to the client */ + } + + ret = 0; + +exit: + /* Cleanup and return */ + if (ssl) + wolfSSL_free(ssl); /* Free the wolfSSL object */ + if (connd != SOCKET_INVALID) + close(connd); /* Close the connection to the client */ + if (sockfd != SOCKET_INVALID) + close(sockfd); /* Close the socket listening for clients */ + if (ctx) + wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */ + wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */ + + return ret; /* Return reporting a success */ +} diff --git a/ebpf/tls-uprobe-trace/wolfssl_uprobe.bpf.c b/ebpf/tls-uprobe-trace/wolfssl_uprobe.bpf.c new file mode 100755 index 000000000..e3e054b96 --- /dev/null +++ b/ebpf/tls-uprobe-trace/wolfssl_uprobe.bpf.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +char LICENSE[] SEC("license") = "GPL"; + +struct wolfssl_event { + __u32 type; // 0 = write, 1 = read + __u32 pid; + __u32 tid; + __u64 ssl_ptr; + __u64 count; // bytes written or read + char comm[16]; + char data[256]; +}; + +#ifdef __TARGET_ARCH_x86 +struct pt_regs { + __u64 r15, r14, r13, r12, rbp, rbx, r11, r10; + __u64 r9, r8, rax, rcx, rdx, rsi, rdi, orig_rax; + __u64 rip, cs, eflags, rsp, ss; +}; +#endif + +#ifdef __TARGET_ARCH_arm64 +struct pt_regs { + __u64 regs[31]; + __u64 sp; + __u64 pc; + __u64 pstate; +}; +#endif + +// Store wolfSSL_read arguments while function executes +struct read_args { + void *buf; + int sz; +}; + +struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); +} events SEC(".maps"); + +// Map to store read function arguments indexed by thread ID +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, __u64); // pid_tgid + __type(value, struct read_args); +} read_args_map SEC(".maps"); + +// wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) +// For ARM64 userspace functions: +// x0 = first arg (ssl) +// x1 = second arg (data) +// x2 = third arg (sz) +SEC("uprobe/wolfSSL_write") +int trace_wolfssl_write_enter(struct pt_regs *ctx) +{ + struct wolfssl_event event = {}; + __u64 pid_tgid; + __u32 pid, tid; + char comm[16]; + long ret; + void *ssl; + void *data; + int sz; + + pid_tgid = bpf_get_current_pid_tgid(); + pid = pid_tgid >> 32; + tid = (__u32)pid_tgid; + + bpf_get_current_comm(&comm, sizeof(comm)); + + // Filter: only trace "client-tls" process + // Manual unrolled comparison to avoid loop issues with verifier + if (comm[0] != 'c' || comm[1] != 'l' || comm[2] != 'i' || + comm[3] != 'e' || comm[4] != 'n' || comm[5] != 't' || + comm[6] != '-' || comm[7] != 't' || comm[8] != 'l' || comm[9] != 's') { + return 0; + } + + // Read function arguments from registers + ssl = (void *)PT_REGS_PARM1(ctx); + data = (void *)PT_REGS_PARM2(ctx); + sz = (int)PT_REGS_PARM3(ctx); + + event.type = 0; // write event + event.pid = pid; + event.tid = tid; + event.ssl_ptr = (__u64)ssl; + event.count = (__u64)sz; + + bpf_get_current_comm(&event.comm, sizeof(event.comm)); + + // Read user buffer data with bounds checking + if (sz > 0 && data != 0) { + unsigned long len = sz; + if (len > 255) { + len = 255; + } + + // Use bpf_probe_read_user to safely read from user space + ret = bpf_probe_read_user(event.data, len, data); + if (ret < 0) { + event.data[0] = '\0'; + } else if (len < 256) { + event.data[len] = '\0'; + } + } else { + event.data[0] = '\0'; + } + + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + return 0; +} + +// wolfSSL_read(WOLFSSL* ssl, void* data, int sz) +// Entry probe - save the arguments for later use in return probe +SEC("uprobe/wolfSSL_read") +int trace_wolfssl_read_enter(struct pt_regs *ctx) +{ + __u64 pid_tgid; + char comm[16]; + struct read_args args = {}; + + pid_tgid = bpf_get_current_pid_tgid(); + bpf_get_current_comm(&comm, sizeof(comm)); + + // Filter: only trace "client-tls" process + if (comm[0] != 'c' || comm[1] != 'l' || comm[2] != 'i' || + comm[3] != 'e' || comm[4] != 'n' || comm[5] != 't' || + comm[6] != '-' || comm[7] != 't' || comm[8] != 'l' || comm[9] != 's') { + return 0; + } + + // Save buffer pointer and size for the return probe + // x0 = ssl (not needed), x1 = buf, x2 = sz + args.buf = (void *)PT_REGS_PARM2(ctx); + args.sz = (int)PT_REGS_PARM3(ctx); + + bpf_map_update_elem(&read_args_map, &pid_tgid, &args, BPF_ANY); + return 0; +} + +// wolfSSL_read return probe - read the decrypted data from the buffer +SEC("uretprobe/wolfSSL_read") +int trace_wolfssl_read_exit(struct pt_regs *ctx) +{ + struct wolfssl_event event = {}; + __u64 pid_tgid; + __u32 pid, tid; + char comm[16]; + struct read_args *args; + int bytes_read; + long ret; + + pid_tgid = bpf_get_current_pid_tgid(); + pid = pid_tgid >> 32; + tid = (__u32)pid_tgid; + + bpf_get_current_comm(&comm, sizeof(comm)); + + // Filter: only trace "client-tls" process + if (comm[0] != 'c' || comm[1] != 'l' || comm[2] != 'i' || + comm[3] != 'e' || comm[4] != 'n' || comm[5] != 't' || + comm[6] != '-' || comm[7] != 't' || comm[8] != 'l' || comm[9] != 's') { + return 0; + } + + // Retrieve the saved arguments + args = bpf_map_lookup_elem(&read_args_map, &pid_tgid); + if (!args) { + return 0; + } + + bytes_read = (int)PT_REGS_RC(ctx); + + // Only process successful reads + if (bytes_read <= 0) { + bpf_map_delete_elem(&read_args_map, &pid_tgid); + return 0; + } + + event.type = 1; // read event + event.pid = pid; + event.tid = tid; + event.ssl_ptr = 0; // We didn't save SSL pointer, but could if needed + event.count = (__u64)bytes_read; + + bpf_get_current_comm(&event.comm, sizeof(event.comm)); + + // Read the decrypted data from the buffer + if (bytes_read > 0 && args->buf != 0) { + unsigned long len = bytes_read; + if (len > 255) { + len = 255; + } + + // Use bpf_probe_read_user to safely read from user space + ret = bpf_probe_read_user(event.data, len, args->buf); + if (ret < 0) { + event.data[0] = '\0'; + } else if (len < 256) { + event.data[len] = '\0'; + } + } else { + event.data[0] = '\0'; + } + + bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event)); + + // Clean up the map entry + bpf_map_delete_elem(&read_args_map, &pid_tgid); + return 0; +} diff --git a/ebpf/tls-uprobe-trace/wolfssl_uprobe.c b/ebpf/tls-uprobe-trace/wolfssl_uprobe.c new file mode 100755 index 000000000..51662bcff --- /dev/null +++ b/ebpf/tls-uprobe-trace/wolfssl_uprobe.c @@ -0,0 +1,335 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct wolfssl_event { + __u32 type; // 0 = write, 1 = read + __u32 pid; + __u32 tid; + __u64 ssl_ptr; + __u64 count; // bytes written or read + char comm[16]; + char data[256]; +}; + +static volatile bool running = true; + +static void sig_handler(int sig) +{ + running = false; +} + +static void handle_event(void *ctx, int cpu, void *data, __u32 data_sz) +{ + struct wolfssl_event *e = data; + + if (e->type == 0) { + // Write event + printf("=== wolfSSL_write() INTERCEPTED ===\n"); + printf("Process: %s (PID: %u, TID: %u)\n", e->comm, e->pid, e->tid); + printf("SSL Pointer: 0x%llx\n", e->ssl_ptr); + printf("Write Count: %llu bytes\n", e->count); + printf("Data (first %zu bytes): ", strlen(e->data)); + + for (int i = 0; i < strlen(e->data) && i < 64; i++) { + char c = e->data[i]; + if (c >= 32 && c <= 126) { + printf("%c", c); + } else { + printf("\\x%02x", (unsigned char)c); + } + } + printf("\n"); + + printf("Data (hex): "); + for (int i = 0; i < strlen(e->data) && i < 32; i++) { + printf("%02x ", (unsigned char)e->data[i]); + } + printf("\n"); + printf("=====================================\n\n"); + } else if (e->type == 1) { + // Read event + printf("=== wolfSSL_read() INTERCEPTED (RETURN) ===\n"); + printf("Process: %s (PID: %u, TID: %u)\n", e->comm, e->pid, e->tid); + printf("Bytes Read: %llu bytes\n", e->count); + printf("Decrypted Data (first %zu bytes): ", strlen(e->data)); + + for (int i = 0; i < strlen(e->data) && i < 64; i++) { + char c = e->data[i]; + if (c >= 32 && c <= 126) { + printf("%c", c); + } else { + printf("\\x%02x", (unsigned char)c); + } + } + printf("\n"); + + printf("Data (hex): "); + for (int i = 0; i < strlen(e->data) && i < 32; i++) { + printf("%02x ", (unsigned char)e->data[i]); + } + printf("\n"); + printf("============================================\n\n"); + } +} + +static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) +{ + printf("Lost %llu events on CPU #%d!\n", lost_cnt, cpu); +} + +static int bump_memlock_rlimit(void) +{ + struct rlimit rlim_new = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; + + if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) { + fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit: %s\n", strerror(errno)); + fprintf(stderr, "You may need to run this program with sudo or adjust system limits.\n"); + return -1; + } + return 0; +} + +static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) +{ + /* Only print warnings and errors */ + if (level <= LIBBPF_WARN) + return vfprintf(stderr, format, args); + return 0; +} + +static long find_symbol_offset(const char *binary_path, const char *symbol_name) +{ + Elf *elf = NULL; + Elf_Scn *scn = NULL; + GElf_Shdr shdr; + int fd = -1; + long offset = -1; + + if (elf_version(EV_CURRENT) == EV_NONE) { + fprintf(stderr, "Failed to init libelf\n"); + return -1; + } + + fd = open(binary_path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Failed to open %s: %s\n", binary_path, strerror(errno)); + return -1; + } + + elf = elf_begin(fd, ELF_C_READ, NULL); + if (!elf) { + fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(-1)); + goto cleanup; + } + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) != &shdr) + continue; + if (shdr.sh_type != SHT_SYMTAB && shdr.sh_type != SHT_DYNSYM) + continue; + + Elf_Data *data = elf_getdata(scn, NULL); + if (!data) + continue; + + int symbols = shdr.sh_size / shdr.sh_entsize; + for (int i = 0; i < symbols; i++) { + GElf_Sym sym; + if (!gelf_getsym(data, i, &sym)) + continue; + const char *name = elf_strptr(elf, shdr.sh_link, sym.st_name); + if (!name) + continue; + if (strcmp(name, symbol_name) == 0) { + offset = sym.st_value; + goto cleanup; + } + } + } + +cleanup: + if (elf) + elf_end(elf); + if (fd >= 0) + close(fd); + + if (offset < 0) + fprintf(stderr, "Failed to locate symbol %s in %s\n", symbol_name, binary_path); + + return offset; +} + +int main(int argc, char **argv) +{ + struct bpf_object *obj; + struct bpf_program *prog_write, *prog_read_enter, *prog_read_exit; + struct bpf_link *link_write, *link_read_enter, *link_read_exit; + struct perf_buffer *pb; + int map_fd; + int err; + char *library_path = "/usr/local/lib/libwolfssl.so.44"; + pid_t target_pid = -1; // -1 means attach to all processes + + if (argc > 1) { + library_path = argv[1]; + } + + /* Set up libbpf logging callback */ + libbpf_set_print(libbpf_print_fn); + + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + printf("Loading eBPF program to trace wolfSSL_write()...\n"); + + /* Check if we're running as root */ + if (geteuid() != 0) { + fprintf(stderr, "Error: This program must be run as root (use sudo).\n"); + fprintf(stderr, "Example: sudo %s\n", argv[0]); + return 1; + } + + /* Bump RLIMIT_MEMLOCK to allow BPF map creation */ + if (bump_memlock_rlimit()) { + fprintf(stderr, "Failed to increase rlimit\n"); + return 1; + } + + printf("Target library: %s\n", library_path); + printf("Attaching to function: wolfSSL_write\n"); + printf("Press Ctrl+C to stop.\n\n"); + + obj = bpf_object__open_file("wolfssl_uprobe.bpf.o", NULL); + if (libbpf_get_error(obj)) { + fprintf(stderr, "Failed to open BPF object file\n"); + return 1; + } + + err = bpf_object__load(obj); + if (err) { + fprintf(stderr, "Failed to load BPF object: %d\n", err); + goto cleanup; + } + + // Find all BPF programs + prog_write = bpf_object__find_program_by_name(obj, "trace_wolfssl_write_enter"); + if (!prog_write) { + fprintf(stderr, "Failed to find wolfSSL_write BPF program\n"); + err = 1; + goto cleanup; + } + + prog_read_enter = bpf_object__find_program_by_name(obj, "trace_wolfssl_read_enter"); + if (!prog_read_enter) { + fprintf(stderr, "Failed to find wolfSSL_read entry BPF program\n"); + err = 1; + goto cleanup; + } + + prog_read_exit = bpf_object__find_program_by_name(obj, "trace_wolfssl_read_exit"); + if (!prog_read_exit) { + fprintf(stderr, "Failed to find wolfSSL_read exit BPF program\n"); + err = 1; + goto cleanup; + } + + long write_offset = find_symbol_offset(library_path, "wolfSSL_write"); + if (write_offset < 0) { + err = 1; + goto cleanup; + } + long read_offset = find_symbol_offset(library_path, "wolfSSL_read"); + if (read_offset < 0) { + err = 1; + goto cleanup; + } + + // Attach uprobe/uretprobe to wolfSSL functions + link_write = bpf_program__attach_uprobe(prog_write, false, target_pid, library_path, + write_offset); + if (libbpf_get_error(link_write)) { + fprintf(stderr, "Failed to attach uprobe to wolfSSL_write\n"); + fprintf(stderr, "Make sure:\n"); + fprintf(stderr, " 1. The library path is correct: %s\n", library_path); + fprintf(stderr, " 2. wolfSSL_write symbol exists in the library\n"); + fprintf(stderr, " 3. You have sufficient permissions (run with sudo)\n"); + err = 1; + goto cleanup; + } + + // Attach uprobe to wolfSSL_read entry + link_read_enter = bpf_program__attach_uprobe(prog_read_enter, false, target_pid, library_path, + read_offset); + if (libbpf_get_error(link_read_enter)) { + fprintf(stderr, "Failed to attach uprobe to wolfSSL_read (entry)\n"); + err = 1; + goto cleanup_write; + } + + // Attach uretprobe to wolfSSL_read exit + link_read_exit = bpf_program__attach_uprobe(prog_read_exit, true, target_pid, library_path, + read_offset); + if (libbpf_get_error(link_read_exit)) { + fprintf(stderr, "Failed to attach uretprobe to wolfSSL_read (exit)\n"); + err = 1; + goto cleanup_read_enter; + } + + map_fd = bpf_object__find_map_fd_by_name(obj, "events"); + if (map_fd < 0) { + fprintf(stderr, "Failed to find events map\n"); + err = 1; + goto cleanup_read_exit; + } + + struct perf_buffer_opts pb_opts = { + .sample_cb = handle_event, + .lost_cb = handle_lost_events, + }; + + pb = perf_buffer__new(map_fd, 8, &pb_opts); + if (libbpf_get_error(pb)) { + fprintf(stderr, "Failed to create perf buffer\n"); + err = 1; + goto cleanup_read_exit; + } + + printf("Successfully loaded and attached eBPF programs!\n"); + printf("Monitoring wolfSSL_write() and wolfSSL_read() calls...\n\n"); + + while (running) { + err = perf_buffer__poll(pb, 100); + if (err < 0 && err != -EINTR) { + fprintf(stderr, "Error polling perf buffer: %d\n", err); + break; + } + } + + printf("\nShutting down...\n"); + + perf_buffer__free(pb); +cleanup_read_exit: + bpf_link__destroy(link_read_exit); +cleanup_read_enter: + bpf_link__destroy(link_read_enter); +cleanup_write: + bpf_link__destroy(link_write); +cleanup: + bpf_object__close(obj); + return err; +}