mirror of
https://github.com/varun-r-mallya/Python-BPF.git
synced 2025-12-31 21:06:25 +00:00
Get ex2 running
This commit is contained in:
4
Makefile
4
Makefile
@ -1,13 +1,13 @@
|
|||||||
compile:
|
compile:
|
||||||
chmod +x ./tools/compile.py
|
chmod +x ./tools/compile.py
|
||||||
./tools/compile.py ./examples/execve.py
|
./tools/compile.py ./examples/execve2.py
|
||||||
|
|
||||||
install:
|
install:
|
||||||
pip install -e .
|
pip install -e .
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf build dist *.egg-info
|
rm -rf build dist *.egg-info
|
||||||
rm -rf examples/execve.ll examples/execve.o
|
rm -rf examples/*.ll examples/*.o
|
||||||
|
|
||||||
all: install compile
|
all: install compile
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,9 @@ Step 2. Run `make` to see the compilation output of the example.
|
|||||||
Step 3. Run `check.sh` to check if generated object file passes through the verifier inside the examples directory.
|
Step 3. Run `check.sh` to check if generated object file passes through the verifier inside the examples directory.
|
||||||
Step 4. Run `make` in the `examples/c-form` directory to modify the example C BPF program to check the actual LLVM IR generated by clang.
|
Step 4. Run `make` in the `examples/c-form` directory to modify the example C BPF program to check the actual LLVM IR generated by clang.
|
||||||
|
|
||||||
|
### Development Notes
|
||||||
|
Run ` ./check.sh run execve2.o;` in examples folder
|
||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
- [@r41k0u](https://github.com/r41k0u)
|
- [@r41k0u](https://github.com/r41k0u)
|
||||||
- [@varun-r-mallya](https://github.com/varun-r-mallya)
|
- [@varun-r-mallya](https://github.com/varun-r-mallya)
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
BPF_CLANG := clang
|
BPF_CLANG := clang
|
||||||
CFLAGS := -O2 -emit-llvm -target bpf -c
|
CFLAGS := -O2 -emit-llvm -target bpf -c
|
||||||
|
|
||||||
SRC := ex3.bpf.c
|
SRC := $(wildcard *.bpf.c)
|
||||||
OUT := ex3.bpf.ll
|
LL := $(SRC:.bpf.c=.bpf.ll)
|
||||||
OBJECT := ex3.bpf.o
|
OBJ := $(SRC:.bpf.c=.bpf.o)
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all: $(OUT)
|
all: $(LL) $(OBJ)
|
||||||
|
|
||||||
object: $(SRC)
|
|
||||||
$(BPF_CLANG) -O2 -g -target bpf -c $< -o $(OBJECT)
|
|
||||||
|
|
||||||
$(OUT): $(SRC) object
|
%.bpf.o: %.bpf.c
|
||||||
|
$(BPF_CLANG) -O2 -target bpf -c $< -o $@
|
||||||
|
|
||||||
|
%.bpf.ll: %.bpf.c
|
||||||
$(BPF_CLANG) $(CFLAGS) -S $< -o $@
|
$(BPF_CLANG) $(CFLAGS) -S $< -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OUT) $(OBJECT)
|
rm -f $(LL) $(OBJ)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
#include <bpf/bpf_helpers.h>
|
#include <bpf/bpf_helpers.h>
|
||||||
|
|
||||||
SEC("kprobe/sys_clone")
|
SEC("tracepoint/syscalls/sys_enter_execve")
|
||||||
int hello(struct pt_regs *ctx) {
|
int hello(struct pt_regs *ctx) {
|
||||||
bpf_printk("Hello, World!\n");
|
bpf_printk("Hello, World!\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -1,2 +1,33 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
sudo bpftool prog -d load $1 /sys/fs/bpf/tmp && sudo rm -f /sys/fs/bpf/tmp
|
|
||||||
|
PIN_PATH="/sys/fs/bpf/bpf_prog"
|
||||||
|
FILE="$2"
|
||||||
|
case "$1" in
|
||||||
|
check)
|
||||||
|
echo "[*] Checking $FILE"
|
||||||
|
echo $(sudo bpftool prog load -d "$FILE" "$PIN_PATH")
|
||||||
|
sudo rm -f "$PIN_PATH"
|
||||||
|
echo "[+] Verification succeeded"
|
||||||
|
;;
|
||||||
|
run)
|
||||||
|
echo "[*] Loading and running $FILE"
|
||||||
|
sudo bpftool prog load "$FILE" "$PIN_PATH" autoattach
|
||||||
|
echo "[+] Program loaded. Press Ctrl+C to stop"
|
||||||
|
sudo cat /sys/kernel/debug/tracing/trace_pipe
|
||||||
|
sudo rm -f "$PIN_PATH"
|
||||||
|
echo "[+] Stopped"
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
echo "[*] Stopping program"
|
||||||
|
sudo rm -f "$PIN_PATH"
|
||||||
|
echo "[+] Stopped"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 <check|run|stop> <file.o>"
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 check program.bpf.o"
|
||||||
|
echo " $0 run program.bpf.o"
|
||||||
|
echo " $0 stop"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
from pythonbpf.decorators import bpf, section
|
from pythonbpf.decorators import bpf, section
|
||||||
# from pythonbpf.decorators import tracepoint, syscalls
|
|
||||||
from ctypes import c_void_p, c_int32
|
from ctypes import c_void_p, c_int32
|
||||||
|
|
||||||
|
|
||||||
@bpf
|
@bpf
|
||||||
@section("kprobe/sys_clone")
|
@section("tracepoint/syscalls/sys_enter_execve")
|
||||||
def hello(ctx: c_void_p) -> c_int32:
|
def hello(ctx: c_void_p) -> c_int32:
|
||||||
print("Hello, World!")
|
print("Hello, World!")
|
||||||
return c_int32(0)
|
return c_int32(0)
|
||||||
|
|
||||||
|
|
||||||
LICENSE = "GPL"
|
LICENSE = "GPL"
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
from pythonbpf.decorators import tracepoint, syscalls
|
# This is what it is going to look like
|
||||||
|
# pylint: disable-all# type: ignore
|
||||||
|
from pythonbpf.decorators import tracepoint, syscalls, bpfglobal, bpf
|
||||||
from ctypes import c_void_p, c_int32
|
from ctypes import c_void_p, c_int32
|
||||||
|
|
||||||
|
@bpf
|
||||||
@tracepoint(syscalls.sys_clone)
|
@tracepoint(syscalls.sys_clone)
|
||||||
def trace_clone(ctx: c_void_p) -> c_int32:
|
def trace_clone(ctx: c_void_p) -> c_int32:
|
||||||
print("Hello, World!")
|
print("Hello, World!")
|
||||||
return c_int32(0)
|
return c_int32(0)
|
||||||
|
|
||||||
|
@bpf
|
||||||
LICENSE = "GPL"
|
@bpfglobal
|
||||||
|
def LICENSE() -> str:
|
||||||
|
return "GPL"
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import ast
|
import ast
|
||||||
from llvmlite import ir
|
from llvmlite import ir
|
||||||
from .license_pass import license_processing
|
from .license_pass import license_processing
|
||||||
from .functions_pass import func_proc, functions_processing
|
from .functions_pass import func_proc
|
||||||
from .constants_pass import constants_processing
|
# from .constants_pass import constants_processing
|
||||||
from .globals_pass import globals_processing
|
from .globals_pass import globals_processing
|
||||||
|
|
||||||
|
|
||||||
@ -28,12 +28,10 @@ def processor(source_code, filename, module):
|
|||||||
|
|
||||||
func_proc(tree, module, bpf_chunks)
|
func_proc(tree, module, bpf_chunks)
|
||||||
# For now, we will parse the BPF specific parts of AST
|
# For now, we will parse the BPF specific parts of AST
|
||||||
# Big rewrite
|
|
||||||
|
|
||||||
# will worry later
|
|
||||||
# constants_processing(tree, module)
|
# constants_processing(tree, module)
|
||||||
# license_processing(tree, module)
|
license_processing(tree, module)
|
||||||
# globals_processing(tree, module)
|
globals_processing(tree, module)
|
||||||
# functions_processing(tree, module)
|
# functions_processing(tree, module)
|
||||||
|
|
||||||
|
|
||||||
@ -57,6 +55,7 @@ def compile_to_ir(filename: str, output: str):
|
|||||||
module.add_named_metadata("llvm.ident", ["llvmlite PythonBPF v0.0.0"])
|
module.add_named_metadata("llvm.ident", ["llvmlite PythonBPF v0.0.0"])
|
||||||
|
|
||||||
with open(output, "w") as f:
|
with open(output, "w") as f:
|
||||||
|
f.write(f"source_filename = \"{filename}\"\n")
|
||||||
f.write(str(module))
|
f.write(str(module))
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|||||||
@ -13,9 +13,9 @@ def emit_function(module: ir.Module, name: str):
|
|||||||
param.add_attribute("nocapture")
|
param.add_attribute("nocapture")
|
||||||
|
|
||||||
func.attributes.add("nounwind")
|
func.attributes.add("nounwind")
|
||||||
# func.attributes.add("\"frame-pointer\"=\"all\"")
|
# func.attributes.add("\"frame-pointer\"=\"all\"")
|
||||||
# func.attributes.add("no-trapping-math", "true")
|
# func.attributes.add("no-trapping-math", "true")
|
||||||
# func.attributes.add("stack-protector-buffer-size", "8")
|
# func.attributes.add("stack-protector-buffer-size", "8")
|
||||||
|
|
||||||
block = func.append_basic_block(name="entry")
|
block = func.append_basic_block(name="entry")
|
||||||
builder = ir.IRBuilder(block)
|
builder = ir.IRBuilder(block)
|
||||||
@ -70,17 +70,17 @@ def process_func_body(module, builder, func_node, func):
|
|||||||
# Handle print statement
|
# Handle print statement
|
||||||
for arg in call.args:
|
for arg in call.args:
|
||||||
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
|
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
|
||||||
fmt_str = arg.value + "\n"
|
fmt_str = arg.value + "\n" + "\0"
|
||||||
# Create a global variable for the format string
|
# Create a global variable for the format string
|
||||||
fmt_gvar = ir.GlobalVariable(
|
fmt_gvar = ir.GlobalVariable(
|
||||||
module, ir.ArrayType(ir.IntType(8), len(fmt_str)), name=f"{func.name}____fmt")
|
module, ir.ArrayType(ir.IntType(8), len(fmt_str)), name=f"{func.name}____fmt")
|
||||||
fmt_gvar.global_constant = True
|
fmt_gvar.global_constant = True
|
||||||
fmt_gvar.initializer = ir.Constant(
|
fmt_gvar.initializer = ir.Constant( # type: ignore
|
||||||
ir.ArrayType(ir.IntType(8), len(fmt_str)),
|
ir.ArrayType(ir.IntType(8), len(fmt_str)),
|
||||||
bytearray(fmt_str.encode("utf8"))
|
bytearray(fmt_str.encode("utf8"))
|
||||||
)
|
)
|
||||||
fmt_gvar.linkage = "internal"
|
fmt_gvar.linkage = "internal"
|
||||||
fmt_gvar.align = 1
|
fmt_gvar.align = 1 # type: ignore
|
||||||
|
|
||||||
# Cast the global variable to i8*
|
# Cast the global variable to i8*
|
||||||
fmt_ptr = builder.bitcast(
|
fmt_ptr = builder.bitcast(
|
||||||
@ -129,6 +129,8 @@ def process_bpf_chunk(func_node, module):
|
|||||||
|
|
||||||
func.linkage = "dso_local"
|
func.linkage = "dso_local"
|
||||||
func.attributes.add("nounwind")
|
func.attributes.add("nounwind")
|
||||||
|
func.attributes.add("noinline")
|
||||||
|
func.attributes.add("optnone")
|
||||||
|
|
||||||
if func_node.args.args:
|
if func_node.args.args:
|
||||||
# Only look at the first argument for now
|
# Only look at the first argument for now
|
||||||
|
|||||||
@ -31,8 +31,8 @@ def globals_processing(tree, module: ir.Module):
|
|||||||
collected = ["LICENSE"]
|
collected = ["LICENSE"]
|
||||||
|
|
||||||
for node in tree.body:
|
for node in tree.body:
|
||||||
if isinstance(node, ast.FunctionDef) and len(node.decorator_list) == 1:
|
if isinstance(node, ast.FunctionDef) and len(node.decorator_list) == 2:
|
||||||
dec = node.decorator_list[0]
|
dec = node.decorator_list[1]
|
||||||
if (
|
if (
|
||||||
isinstance(dec, ast.Call)
|
isinstance(dec, ast.Call)
|
||||||
and isinstance(dec.func, ast.Name)
|
and isinstance(dec.func, ast.Name)
|
||||||
|
|||||||
@ -14,7 +14,7 @@ def main():
|
|||||||
codegen.compile_to_ir(args.source, ll_file)
|
codegen.compile_to_ir(args.source, ll_file)
|
||||||
|
|
||||||
print("[+] Running llc -march=bpf")
|
print("[+] Running llc -march=bpf")
|
||||||
subprocess.run(["llc", "-march=bpf", "-filetype=obj", ll_file, "-o", o_file], check=True)
|
subprocess.run(["llc", "-march=bpf", "-filetype=obj", "-O2", ll_file, "-o", o_file], check=True)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user