Skip to content

fix: ensure eBPF verifier compliance by adding explicit fallback returns after tail calls#16

Merged
congwang-mk merged 1 commit into
multikernel:mainfrom
SiyuanSun0736:fix_tail_call
Mar 29, 2026
Merged

fix: ensure eBPF verifier compliance by adding explicit fallback returns after tail calls#16
congwang-mk merged 1 commit into
multikernel:mainfrom
SiyuanSun0736:fix_tail_call

Conversation

@SiyuanSun0736
Copy link
Copy Markdown
Contributor

Problem Definition
The bpf_tail_call() helper in eBPF is not guaranteed to succeed. If the call fails (e.g., due to an invalid index or exceeding the call stack limit), execution continues at the instruction immediately following the call site. The eBPF verifier requires that every code path reaches a definitive termination point. Without an explicit return after a tail call, the verifier may reject the program as it cannot guarantee all paths exit.

Mechanism of Change
A new helper function get_tail_call_fallback_return has been implemented to determine the correct return value based on the program's execution context. This ensures that the generated C code includes a fallback return statement immediately following every bpf_tail_call.

Context Mapping Logic
The return value is determined by the current_function_context_type variable:

Context Type (Some string) Fallback Return Value
"xdp" XDP_PASS
"tc" TC_ACT_OK
None / Other 0

Technical Breakdown

  1. Code Generation: The logic modifies the emission of IRReturnTailCall and IRReturnCall.
  2. Instrumentation: Adds a C comment /* tail call fallback */ to the emitted return statement for traceability and debugging.
  3. Instruction Support:
    • IRReturnTailCall: Explicit tail calls with specific indices.
    • IRReturnCall: Generic calls mapped to tail call index 0.
    • Match Arms: Coverage for both IRConstantPattern and IRDefaultPattern within IRMatchReturn instructions.

Verification Results

The implementation is verified via the following OCaml unit tests:

  • test_tail_call_fallback_constant_arm_xdp: Confirms that in an XDP context, a constant match arm containing a tail call generates return XDP_PASS;.
  • test_tail_call_fallback_default_arm_tc: Confirms that in a TC context, a default match arm generates return TC_ACT_OK;.
  • test_return_call_fallback_generic_context: Confirms that when the context is undefined, the generator defaults to return 0; and correctly handles implicit tail calls (index 0).

Copilot AI review requested due to automatic review settings March 19, 2026 11:52
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the eBPF C code generator to satisfy verifier requirements by emitting an explicit fallback return immediately after any bpf_tail_call() emitted from IRMatchReturn arms, ensuring all control-flow paths terminate even if the tail call fails at runtime.

Changes:

  • Added get_tail_call_fallback_return to map the current function context (xdp/tc/other) to an appropriate return constant (XDP_PASS / TC_ACT_OK / 0).
  • Updated IRMatchReturn codegen for both constant and default arms so IRReturnCall and IRReturnTailCall emit return <fallback>; /* tail call fallback */ after bpf_tail_call(...).
  • Added unit tests covering XDP, TC, and generic contexts, and verifying the legacy “continue execution” comment is no longer emitted for these return-position tail calls.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/ebpf_c_codegen.ml Adds context-aware fallback return selection and emits explicit fallback returns after tail calls within IRMatchReturn arms.
tests/test_ebpf_c_codegen.ml Adds regression tests validating tail call fallback return emission across XDP/TC/generic contexts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@SiyuanSun0736
Copy link
Copy Markdown
Contributor Author

I merged upstream/master and resolved the conflicts.

@congwang-mk
Copy link
Copy Markdown
Contributor

I merged upstream/master and resolved the conflicts.

Could you rebase?

@SiyuanSun0736
Copy link
Copy Markdown
Contributor Author

I have finished the rebase.

@congwang-mk
Copy link
Copy Markdown
Contributor

The standalone IRTailCall instruction (not inside a match arm) still has the old "/* If tail call fails, continue execution */" comment and no fallback return. This is the same bug, just in a different code path. The fix is incomplete.

…l paths have an explicit return in the event that `bpf_tail_call()` fails.

Add relevant tests.

Also: fix standalone IRTailCall codegen path — emit a context-aware fallback return after bpf_tail_call() to satisfy the eBPF verifier. Added regression test test_standalone_tail_call_fallback_xdp and included it in the suite. Ran tests/test_ebpf_c_codegen.exe (41 tests) — all passed.
@SiyuanSun0736
Copy link
Copy Markdown
Contributor Author

standalone IRTailCall code path has been updated to emit the same context-aware fallback return as the match-arm path, and a regression test was added for the non-match tail-call case.

@congwang-mk congwang-mk merged commit 1757eb9 into multikernel:main Mar 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants