BPF (eBPF / bpftools / BCC)¶
very-very-very greate references
Setup¶
install tool-cahin
sudo apt-get install -y \
bpfcc-tools python3-bpfcc \
linux-headers-`uname -r`
BCC¶
hook clone
#!/usr/bin/python3
from bcc import BPF
text="""
int kprobe__sys_clone(void *ctx) {
bpf_trace_printk("Hello, World!\\n");
return 0;
}
"""
BPF(text=text).trace_print()
bpftools¶
build and install bpftool (kernel-version: 4.18.0)
sudo apt install \
linux-image-4.18.0-13-generic \
linux-modules-4.18.0-13-generic \
linux-modules-extra-4.18.0-13-generic \
linux-tools-4.18.0-13-generic \
build-essential binutils-dev libelf-dev
export WORK=~/Desktop/work
cp /usr/src/linux-source-4.18.0.tar.bz2 $WORK && cd $_
tar xpf linux-source-4.18.0.tar.bz2
make -C linux-source-4.18.0/tools/bpf/bpftool
sudo cp linux-source-4.18.0/tools/bpf/bpftool/bpftool /usr/local/bin
bpftool --version
check bpf program
sudo bpftool prog
...(snip)
14: kprobe name sys_clone tag c514db71faba4034 gpl
loaded_at 2019-07-08T15:53:10+0000 uid 0
xlated 120B jited 115B memlock 4096B
...(snip)
sudo bpftool prog dump xlated id 14
0: (b7) r1 = 2593
1: (6b) *(u16 *)(r10 -4) = r1
2: (b7) r1 = 1684828783
3: (63) *(u32 *)(r10 -8) = r1
4: (18) r1 = 0x57202c6f6c6c6548
6: (7b) *(u64 *)(r10 -16) = r1
7: (b7) r1 = 0
8: (73) *(u8 *)(r10 -2) = r1
9: (bf) r1 = r10
10: (07) r1 += -16
11: (b7) r2 = 15
12: (85) call bpf_trace_printk#-47744
13: (b7) r0 = 0
14: (95) exit
sudo bpftool map
2: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
3: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
4: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
5: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
6: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
7: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
eBPF-MAP Array¶
monitoring user process’s call info about malloc / free.
#!/usr/bin/python
import sys
from bcc import BPF
from time import sleep
if len(sys.argv) < 2:
print("Usage: {} <PID>".format(sys.argv[0]))
exit()
bpf_text="""
#include <uapi/linux/ptrace.h>
#define MALLOC 0
#define FREE 1
BPF_ARRAY(count, u64, 2);
void trace_malloc(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid();
if (pid != PID)
return;
bpf_trace_printk("good\\n");
count.increment(MALLOC);
}
void trace_free(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid();
if (pid != PID)
return;
bpf_trace_printk("bad\\n");
count.increment(FREE);
}
"""
bpf_text = bpf_text.replace("PID", sys.argv[1])
b = BPF(text=bpf_text)
print("comple ...done")
b.attach_uprobe(
name = "c",
sym="malloc",
fn_name="trace_malloc")
b.attach_uprobe(
name = "c",
sym="free",
fn_name="trace_free")
while True:
malloc = b["count"][0].value
free = b["count"][1].value
print("{} / {}".format(malloc, free))
sleep(1)
sudo ./main.py 9786
compile ...done
...(snip)
7 / 0
10 / 0
14 / 0
17 / 0
20 / 0
...(snip)
we can also check table w/ bpftool
sudo bpftool map
2: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
3: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
4: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
5: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
6: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
7: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
46: array name count flags 0x0
key 4B value 8B max_entries 2 memlock 4096B
sudo bpftool map dump id 46
key: 00 00 00 00 value: 7d 00 00 00 00 00 00 00
key: 01 00 00 00 value: 00 00 00 00 00 00 00 00
Found 2 elements
we can also check table via another BCC script
#!/usr/bin/python
from bcc import libbcc, table
import ctypes
import sys
class PinnedArray(table.Array):
def __init__(self, map_path, keytype, leaftype, max_entries):
map_fd = libbcc.lib.bpf_obj_get(ctypes.c_char_p(map_path))
if map_fd < 0:
raise ValueError("Failed to open eBPF map")
self.map_fd = map_fd
self.Key = keytype
self.Leaf = leaftype
self.max_entries = max_entries
counter = PinnedArray(
map_path = "/sys/fs/bpf/count",
keytype = ctypes.c_uint32,
leaftype = ctypes.c_long,
max_entries = 1)
print(counter[0].value)
TO-READ¶
- XDPのサンプルコードを含め, 基本的なHandsonを含んでいる https://rheb.hatenablog.com/entry/xdp1 https://rheb.hatenablog.com/entry/xdp2