Skip to content

Instantly share code, notes, and snippets.

@lizrice
Last active July 19, 2023 08:20
Show Gist options
  • Save lizrice/47ad44a15cce912502f8667a403f5649 to your computer and use it in GitHub Desktop.
Save lizrice/47ad44a15cce912502f8667a403f5649 to your computer and use it in GitHub Desktop.
eBPF hello world
#!/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.
@lizrice
Copy link
Author

lizrice commented Jun 4, 2019

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

@lizrice
Copy link
Author

lizrice commented Nov 5, 2019

See also Aqua Security's Tracee project

@yashbhutwala
Copy link

yashbhutwala commented Dec 15, 2019

@lizrice can you please also attach the Vagrantfile used for this?

@surajkjai
Copy link

surajkjai commented Jan 30, 2020

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

@bechampion
Copy link

this is great, a bit from a different angle, can you list what ebpf programs are attached to a given syscall from user land?

@dorazouri
Copy link

dorazouri commented Oct 4, 2020

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

@VRanga000
Copy link

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.

@lizrice
Copy link
Author

lizrice commented Aug 20, 2021 via email

@rodolk
Copy link

rodolk commented Oct 29, 2021

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.

@lizrice
Copy link
Author

lizrice commented Nov 8, 2021

@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

@rodolk
Copy link

rodolk commented Nov 10, 2021

@lizrice Thank you for taking the time to explain me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment