Conversation

Jarkko Sakkinen

Edited 1 month ago

Here’s a minimal shenanigans for #eBPF #C host, with bpftool taking care of header generation.

Payload (payload.c):

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
SEC("tracepoint/syscalls/sys_enter_execve")
int tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter *ctx)
{
	bpf_printk("execve");
	return 0;
}
char LICENSE[] SEC("license") = "GPL";

Host (main.c):

#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <signal.h>
#include "payload.h"

static volatile bool interrupted = false;
struct payload *obj;

void do_sigint(int value)
{
	interrupted = true;
}

int main(void)
{
	struct sigaction sa;
	ssize_t ret;

	obj = payload__open();
	if (!obj)
		exit(1);

	ret  = payload__load(obj);
	if (ret)
		goto err;

	ret = payload__attach(obj);
	if (ret)
		goto err;

	sa.sa_handler = do_sigint;
	sigaction(SIGINT, &sa, NULL);
	while (!interrupted);
	fprintf(stderr, "\ndone\n");
	payload__destroy(obj);	
	exit(0);

err:
	payload__destroy(obj);	
	exit(1);
}

Build (build.sh):

#!/usr/bin/env sh

# vmlinux
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

# payload
clang -g -O2 -target bpf -I . -c payload.c -o payload.o
bpftool gen skeleton payload.o > payload.h

# main
clang -g -O2 -Wall -I . -c main.c -o main.o

# hello-ebpf
clang -Wall -O2 -g main.o -lbpf -lelf -lz -o hello-ebpf

While running trace_pipe is expected to have output like this:

             cat-61135   [011] ....1  8303.116335: bpf_trace_printk: execve
             zsh-61136   [002] ....1  8303.116691: bpf_trace_printk: execve
             zsh-61139   [004] ....1  8303.118436: bpf_trace_printk: execve

#linux #kernel #tracing

1
1
2
Just wanted to go through how it is done without any external tools and/or abstraction layers, so now I know... ☑️
1
0
0

Jarkko Sakkinen

Edited 1 month ago

I’ll try next open coding sudo bpftrace -e 'kprobe:tpm_transmit { @[kstack] = count(); }'.

I.e. probably something like this (at least compiles and loads):

#include "vmlinux.h"
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

char LICENSE[] SEC("license") = "GPL";

struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__type(key, int);
	__type(value, int);
	__uint(max_entries, 100);
} tpm_transmits SEC(".maps");

SEC("kprobe/tpm_transmit")
int BPF_KPROBE(kprobe__tpm_transmit, struct pt_regs *regs)
{
	/* TODO: update tpm_transmits map */
	return 0;
}

Also, kprobe requires target architecture, so the object file is now compiled as follows:

clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -c payload.c

Binary has now a symbol for maps:

~/work/local/ebpf master*
❯ nm payload.o
0000000000000000 T kprobe__tpm_transmit
0000000000000000 r ____kprobe__tpm_transmit.____fmt
0000000000000000 D LICENSE
0000000000000000 D tpm_transmits

I don’t have any particular use for eBPF but it is nice to get a bit more in-depth picture on the topic…

1
0
0
Backed up for future revisit with tpm_transmit() histogram: https://codeberg.org/jarkko/hello-ebpf. I learned something :-)
0
0
0