Kernel probes
Reading TCP packets
In the previous exercise, we used kprobes to track TCP connection completion. Now we’ll intercept HTTP data as it’s sent.
We could attach to the sendto() syscall, but that also intercepts vsock transfers, which includes DEBUG_* calls, making for a pretty awkward experience.
Also, it wouldn’t fit the kprobe chapter at all!
Instead, let’s attach to tcp_sendmsg() which is only called for TCP traffic.
Reading data from tcp_sendmsg
We can find the signature for tcp_sendmsg in net/ipv4/tcp.c, which is:
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
And we can access the userspace buffer from the msg parameter, but it’s a bit involved.
A simplified definition of struct msghdr:
struct msghdr {
struct iov_iter msg_iter; // Iterator containing buffer info
// ...
};
struct iov_iter {
union {
struct iovec __ubuf_iovec; // Userspace buffer base/len
// ...
};
};
struct iovec {
void *iov_base;
u64 iov_len;
};
So we’ll read the userspace buffer whose address is stored in msg->msg_iter->__ubuf_iovec.iov_base.
Remember that we can’t dereference pointers directly, so you’ll manually need to read through each indirection level. Keep in mind the address space for each pointer.
HTTP request structure
HTTP requests are text-based:
POST /api/data HTTP/1.1
Host: example.com
Authorization: Bearer secret_token_here
Content-Type: application/json
Headers are separated by \r\n (CRLF). Each header is Name: Value.
In the past, operating on any string-based protocol in eBPF was extremely tedious. Lucky you, since Jun 2025, we can do some string operations directly.
We’ll be using two functions in this exercise:
bpf_strstr(char *haystack, char *needle): Find substring, returns index or negative on errorbpf_strchr(char* str, char c): Find character, returns index or negative on error
For example,
int auth_pos = bpf_strstr(buf, "Authorization: Bearer ");
auth_pos will contain the position of the needle, if found.
With a little bit of math, you can find where the token is supposed to start,
and read from there to the end of the line (marked by \r).
To get to the end, you can use
int token_pos = bpf_strchr(&buf[token_start], '\r');
which will give you the position for the first \r, starting from token_ptr.
The challenge
A program makes an HTTP request with an Authorization: Bearer <token> header.
Your task
Submit the token from the header.
Extract the Nth parameter from kprobe context
- Args:
struct pt_regs* ctxkprobe context containing CPU registers
Read string from user space into kernel buffer
- Args:
void* dstkernel buffer to read intou32 sizemaximum bytes to readconst void* srcuser space pointer to string
Read bytes from user space into kernel buffer
- Args:
void* dstkernel buffer to read intou32 sizebytes to readconst void* srcuser space pointer
Read bytes from kernel space into kernel buffer
- Args:
void* dstkernel buffer to read intou32 sizebytes to readconst void* srckernel space pointer
Read string from kernel space into kernel buffer
- Args:
void* dstkernel buffer to read intou32 sizemaximum bytes to readconst void* srckernel space pointer to string