{"id":20115527,"url":"https://github.com/asphaltt/ebpf-vm-on-ebpf","last_synced_at":"2025-05-06T13:32:55.228Z","repository":{"id":214941383,"uuid":"737703643","full_name":"Asphaltt/ebpf-vm-on-ebpf","owner":"Asphaltt","description":"Build a feature-less eBPF vm on eBPF, just for fun.","archived":false,"fork":false,"pushed_at":"2024-03-10T16:01:17.000Z","size":872,"stargazers_count":15,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-17T23:59:05.145Z","etag":null,"topics":["ebpf","ebpf-vm","ebpf-vm-on-ebpf"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Asphaltt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-01-01T06:37:50.000Z","updated_at":"2024-03-11T15:09:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"3f359b76-c285-41e5-a2d8-92e083e8bf23","html_url":"https://github.com/Asphaltt/ebpf-vm-on-ebpf","commit_stats":null,"previous_names":["asphaltt/ebpf-vm-on-ebpf"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Asphaltt%2Febpf-vm-on-ebpf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Asphaltt%2Febpf-vm-on-ebpf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Asphaltt%2Febpf-vm-on-ebpf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Asphaltt%2Febpf-vm-on-ebpf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Asphaltt","download_url":"https://codeload.github.com/Asphaltt/ebpf-vm-on-ebpf/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224505572,"owners_count":17322627,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ebpf","ebpf-vm","ebpf-vm-on-ebpf"],"created_at":"2024-11-13T18:35:33.633Z","updated_at":"2024-11-13T18:35:34.350Z","avatar_url":"https://github.com/Asphaltt.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Build a feature-less eBPF vm on eBPF\n\nIf bpf prog can run for long time, what do you want to do?\n\nI want to build an eBPF vm on eBPF, even though it's a feature-less\nvm, just for fun.\n\n## What is eBPF vm on eBPF?\n\neBPF vm on eBPF is an eBPF vm, which is implemented by eBPF. As a result, this\nvm is able to reuse most existing eBPF instructions, and then execute\nthe instruction one by one by interpreter way.\n\nAfter implementing this vm, there are following instructions unsupported:\n\n- `BPF_PROBE_MEM` related instructions\n- atomic related instructions\n- non-bpf2bpf call related instructions, including tailcall\n\nUnlike ebpf, eBPF vm on eBPF is unable to access the memory directly, so it limits to access specified stack memory only. As a result, it is unable to support\nbpf maps and bpf helpers. This is the reason why it is a feature-less eBPF vm.\n\n## How to build eBPF vm on eBPF?\n\neBPF vm on eBPF is a vm, which combines with following parts:\n\n- Programs part: it caches bpf progs to be executed.\n- Stack memory space: it is used to store temporary data.\n- Registers: it is used to store temporary variables.\n- Interpreter: it is used to execute bpf instructions one by one.\n\nAnd, the bpf instructions limit to operate stack memory space and registers.\n\n## How about function call?\n\nCan eBPF vm on eBPF support function call? The answer is yes, but it supports\nbpf2bpf funcation call only.\n\nIt does not support tailcall, because it is unable to access bpf maps and call\nbpf helpers.\n\nAs we know, in bpf C code, `__noinline` indicates that the function is not to be\ninlined while compiling. So, if we want to call a function in this vm, we need\nto add `__noinline` to the callee function.\n\nAs a result, after we manipulate bpf2bpf function calls relationship in user\nspace, we save them to programs part of the vm. Then, when the vm executes the\nCALL instruction:\n\n- cache current instruction position\n- cache current stack pointer\n- adjust stack pointer\n- jump to the callee function\n\nWhen the callee function returns, the vm executes the RET instruction:\n\n- restore stack pointer\n- restore instruction position\n- jump to the next instruction\n\nWhen the vm executes the RET instruction, it has to recognize whether the\ncaller function is the main function or not. If it is the main function, the vm\nshould exit immediately.\n\n## Calculate Fibonacci numbers with eBPF vm on eBPF\n\nHow about calculating Fibonacci numbers with eBPF vm on eBPF? The answer is yes.\n\n```c\nSEC(\"xdp\")\nint xdp_fib(struct xdp_md *ctx)\n{\n    volatile int fibs[10];\n    fibs[0] = 1;\n    fibs[1] = 1;\n\n    for (int i = 2; i \u003c 10; i++) {\n        fibs[i] = fibs[i - 1] + fibs[i - 2];\n    }\n\n    return fibs[9];\n}\n```\n\nAfter compiling the above bpf C code with clang, dump the object file with\n[cilium/ebpf dump](https://pkg.go.dev/github.com/cilium/ebpf@v0.12.3/asm#Instructions.Format):\n\n```asm\nxdp_fib:\n      ; int xdp_fib(struct xdp_md *ctx)\n     0: MovImm dst: r1 imm: 1\n      ; fibs[0] = 1;\n     1: StXMemW dst: rfp src: r1 off: -4 imm: 0\n      ; fibs[1] = 1;\n     2: StXMemW dst: rfp src: r1 off: -8 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n     3: LdXMemW dst: r1 src: rfp off: -8 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n     4: LdXMemW dst: r2 src: rfp off: -4 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n     5: AddReg dst: r2 src: r1\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n     6: StXMemW dst: rfp src: r2 off: -12 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n     7: LdXMemW dst: r1 src: rfp off: -12 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n     8: LdXMemW dst: r2 src: rfp off: -8 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n     9: AddReg dst: r2 src: r1\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    10: StXMemW dst: rfp src: r2 off: -16 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    11: LdXMemW dst: r1 src: rfp off: -16 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    12: LdXMemW dst: r2 src: rfp off: -12 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    13: AddReg dst: r2 src: r1\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    14: StXMemW dst: rfp src: r2 off: -20 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    15: LdXMemW dst: r1 src: rfp off: -20 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    16: LdXMemW dst: r2 src: rfp off: -16 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    17: AddReg dst: r2 src: r1\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    18: StXMemW dst: rfp src: r2 off: -24 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    19: LdXMemW dst: r1 src: rfp off: -24 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    20: LdXMemW dst: r2 src: rfp off: -20 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    21: AddReg dst: r2 src: r1\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    22: StXMemW dst: rfp src: r2 off: -28 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    23: LdXMemW dst: r1 src: rfp off: -28 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    24: LdXMemW dst: r2 src: rfp off: -24 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    25: AddReg dst: r2 src: r1\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    26: StXMemW dst: rfp src: r2 off: -32 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    27: LdXMemW dst: r1 src: rfp off: -32 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    28: LdXMemW dst: r2 src: rfp off: -28 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    29: AddReg dst: r2 src: r1\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    30: StXMemW dst: rfp src: r2 off: -36 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    31: LdXMemW dst: r1 src: rfp off: -36 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    32: LdXMemW dst: r2 src: rfp off: -32 imm: 0\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    33: AddReg dst: r2 src: r1\n      ; fibs[i] = fibs[i - 1] + fibs[i - 2];\n    34: StXMemW dst: rfp src: r2 off: -40 imm: 0\n      ; return fibs[9];\n    35: LdXMemW dst: r0 src: rfp off: -40 imm: 0\n    36: Exit\n```\n\nAfter saving the above instructions to the programs part of the vm, the vm\nexecutes the instructions one by one, and then gets the result:\n\n```bash\nbpf_trace_printk: bpf_vm: R0=55\n```\n\nHow about using bpf2bpf function call?\n\n```c\nstatic __noinline int\n__add(int a, int b)\n{\n    volatile int sum = a + b;\n    return sum;\n}\n\nSEC(\"xdp\")\nint xdp_fib2(struct xdp_md *ctx)\n{\n    volatile int fibs[10];\n    fibs[0] = 1;\n    fibs[1] = 1;\n\n    for (int i = 2; i \u003c 10; i++) {\n        fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    }\n\n    return fibs[9];\n}\n```\n\nAfter compiling the above bpf C code with clang, dump the object file with\n[cilium/ebpf dump](https://pkg.go.dev/github.com/cilium/ebpf@v0.12.3/asm#Instructions.Format):\n\n```asm\nxdp_fib2:\n      ; int xdp_fib2(struct xdp_md *ctx)\n     0: MovImm dst: r1 imm: 1\n      ; fibs[0] = 1;\n     1: StXMemW dst: rfp src: r1 off: -4 imm: 0\n      ; fibs[1] = 1;\n     2: StXMemW dst: rfp src: r1 off: -8 imm: 0\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n     3: LdXMemW dst: r1 src: rfp off: -8 imm: 0\n     4: LdXMemW dst: r2 src: rfp off: -4 imm: 0\n     5: Call -1 \u003c__add\u003e\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n     6: StXMemW dst: rfp src: r0 off: -12 imm: 0\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n     7: LdXMemW dst: r1 src: rfp off: -12 imm: 0\n     8: LdXMemW dst: r2 src: rfp off: -8 imm: 0\n     9: Call -1 \u003c__add\u003e\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    10: StXMemW dst: rfp src: r0 off: -16 imm: 0\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    11: LdXMemW dst: r1 src: rfp off: -16 imm: 0\n    12: LdXMemW dst: r2 src: rfp off: -12 imm: 0\n    13: Call -1 \u003c__add\u003e\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    14: StXMemW dst: rfp src: r0 off: -20 imm: 0\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    15: LdXMemW dst: r1 src: rfp off: -20 imm: 0\n    16: LdXMemW dst: r2 src: rfp off: -16 imm: 0\n    17: Call -1 \u003c__add\u003e\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    18: StXMemW dst: rfp src: r0 off: -24 imm: 0\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    19: LdXMemW dst: r1 src: rfp off: -24 imm: 0\n    20: LdXMemW dst: r2 src: rfp off: -20 imm: 0\n    21: Call -1 \u003c__add\u003e\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    22: StXMemW dst: rfp src: r0 off: -28 imm: 0\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    23: LdXMemW dst: r1 src: rfp off: -28 imm: 0\n    24: LdXMemW dst: r2 src: rfp off: -24 imm: 0\n    25: Call -1 \u003c__add\u003e\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    26: StXMemW dst: rfp src: r0 off: -32 imm: 0\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    27: LdXMemW dst: r1 src: rfp off: -32 imm: 0\n    28: LdXMemW dst: r2 src: rfp off: -28 imm: 0\n    29: Call -1 \u003c__add\u003e\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    30: StXMemW dst: rfp src: r0 off: -36 imm: 0\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    31: LdXMemW dst: r1 src: rfp off: -36 imm: 0\n    32: LdXMemW dst: r2 src: rfp off: -32 imm: 0\n    33: Call -1 \u003c__add\u003e\n      ; fibs[i] = __add(fibs[i - 1], fibs[i - 2]);\n    34: StXMemW dst: rfp src: r0 off: -40 imm: 0\n      ; return fibs[9];\n    35: LdXMemW dst: r0 src: rfp off: -40 imm: 0\n    36: Exit\n__add:\n      ; volatile int sum = a + b;\n    37: AddReg dst: r2 src: r1\n      ; volatile int sum = a + b;\n    38: StXMemW dst: rfp src: r2 off: -4 imm: 0\n      ; return sum;\n    39: LdXMemW dst: r0 src: rfp off: -4 imm: 0\n    40: Exit\n```\n\nIt is used to verify whether the vm supports bpf2bpf function call or not.\n\nAfter saving the above instructions to the programs part of the vm, the vm\nexecutes the instructions one by one, and then gets the result:\n\n```bash\nbpf_trace_printk: bpf_vm: R0=55\n```\n\n## Is eBPF vm on eBPF useful?\n\nIt seems useless.\n\nThe issues that can be resolved by eBPF vm on eBPF, can be resolved by eBPF,\ntoo.\n\nBut, without strict verification, the vm is able to execute any bpf code which\nis compiled by clang. As a result, it is able to execute malicious bpf code,\nwhich is compiled by clang, too.\n\nCan this vm execute many bpf instructions?\n\nYes, by using `bpf_loop()` helper to run for long time.\n\n## Comments\n\neBPF vm on eBPF is a really insteresting idea. I've implemented its demo to run\nthe above Fibonacci numbers calculating bpf code.\n\nJust for fun.\n\n## Licenses\n\n**Apache 2.0** license for Go code.\n**GPL 2.0** license for bpf code.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasphaltt%2Febpf-vm-on-ebpf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasphaltt%2Febpf-vm-on-ebpf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasphaltt%2Febpf-vm-on-ebpf/lists"}