-
-
Save lizrice/47ad44a15cce912502f8667a403f5649 to your computer and use it in GitHub Desktop.
#!/usr/bin/python | |
from bcc import BPF | |
from time import sleep | |
# This outputs a count of how many times the clone and execve syscalls have been made | |
# showing the use of an eBPF map (called syscall). | |
program = """ | |
BPF_HASH(syscall); | |
int kprobe__sys_clone(void *ctx) { | |
u64 counter = 0; | |
u64 key = 56; | |
u64 *p; | |
p = syscall.lookup(&key); | |
// The verifier will reject access to a pointer if you don't check that it's non-null first | |
// Try commenting out the if test (and its closing brace) if you want to see the verifier do its thing | |
if (p != 0) { | |
counter = *p; | |
} | |
counter++; | |
syscall.update(&key, &counter); | |
return 0; | |
} | |
int kprobe__sys_execve(void *ctx) { | |
u64 counter = 0; | |
u64 key = 59; | |
u64 *p; | |
p = syscall.lookup(&key); | |
if (p != 0) { | |
counter = *p; | |
} | |
counter++; | |
syscall.update(&key, &counter); | |
return 0; | |
} | |
""" | |
b = BPF(text=program) | |
while True: | |
sleep(2) | |
line = "" | |
for k, v in b["syscall"].items(): | |
line += "syscall {0}: {1}\t".format(k.value, v.value) | |
print(line) |
#!/usr/bin/python | |
from bcc import BPF | |
prog = """ | |
int hello(void *ctx) { | |
bpf_trace_printk("Hello world\\n"); | |
return 0; | |
} | |
""" | |
b = BPF(text=prog) | |
clone = b.get_syscall_fnname("clone") | |
b.attach_kprobe(event=clone, fn_name="hello") | |
b.trace_print() | |
# This prints out a trace line every time the clone system call is called | |
# If you rename hello() to kprobe__sys_clone() you can delete the b.attach_kprobe() line, because bcc can work | |
# out what event to attach this to from the function name. |
See also Aqua Security's Tracee project
@lizrice can you please also attach the Vagrantfile used for this?
Seems BPF's class method attach_kprobe() is broken: the current hello_map.py throws the following exception in python2.7:
Exception: Failed to attach BPF program hello to kprobe__sys_clone
Workaround: as mentioned in the code, comment out b.attach_kprobe() and rename hello to kprobe__sys_clone
this is great, a bit from a different angle, can you list what ebpf programs are attached to a given syscall from user land?
this is great, a bit from a different angle, can you list what ebpf programs are attached to a given syscall from user land?
I think what you are aiming at is bpftool
, as shown in this BPF overview talk by Brendan Gregg @brendangregg:
https://youtu.be/7pmXdG8-7WU?t=1714
These examples use bcc which makes it easy to load eBPF programs into the kernel. I would recommend starting with hello_world.py and then hello_map.py.
Try running them under strace to see the system calls that are happening! For example
strace -e bpf ./hello_world.py
will show you the bpf() system call that loads the program into the kernel (BPF_PROG_LOAD).You can see the accompanying slides from DockerCon here
Thanks for this tutorial and all your awesome tutorials! Your link to bcc is broken - fixed in the quoted text above.
Thank you for the example!
In my Ubuntu I had the error:
cannot attach kprobe, probe entry may not exist
Traceback (most recent call last):
File "h.py", line 12, in <module>
b.attach_kprobe(event="sys_clone", fn_name="hello")
File "/usr/lib/python3/dist-packages/bcc/__init__.py", line 658, in attach_kprobe
raise Exception("Failed to attach BPF program %s to kprobe %s" %
Exception: Failed to attach BPF program b'hello' to kprobe b'sys_clone'
I modified attach_probe first parameter to:
b.attach_kprobe(event="__x64_sys_clone", fn_name="hello")
Then it worked.
@rodolk a more portable way to do this is to use b.get_syscall_fnname("clone")
- I've updated the gist to do that now
@lizrice Thank you for taking the time to explain me!
These examples use bcc which makes it easy to load eBPF programs into the kernel. I would recommend starting with hello_world.py and then hello_map.py.
Try running them under strace to see the system calls that are happening! For example
strace -e bpf ./hello_world.py
will show you the bpf() system call that loads the program into the kernel (BPF_PROG_LOAD).You can see the accompanying slides from DockerCon here