Skip to content

Commit 6d5e323

Browse files
author
brianph
committed
fix(loader): patch kfunc calls in .text subroutines, not just xdp section
Alpha.18 emits verify_ping_token and verify_session_header as #[inline(never)] BPF subroutines, placing them in the .text section with their kfunc calls relocated via .rel.text. The previous loader only walked .relxdp and patched the xdp section, so kfunc calls inside .text retained src_reg=1 (BPF_PSEUDO_CALL) with imm=-1. aya-obj's relocate_calls() then treated them as BPF-to-BPF calls with self-referential pc-relative targets, causing: error relocating verify_ping_token function 0x18 not found while relocating ... (0x18 = 24 = byte offset of the first call instruction in the function.) Fix: - code_relocation_tables(): new helper enumerating every code section (xdp, .text, .text.*) and its sibling .rel<section> table. patch_elf_skip_kfuncs, patch_elf_bpf_helpers, and patch_elf_map_fds now iterate all of them. - patch_elf_skip_kfuncs: in addition to flipping src_reg 1->2, encodes the kfunc index (position in RELAY_MODULE_KFUNCS) into the imm field. - patch_kfunc_instructions: identifies each src_reg=2 call by reading imm back as the kfunc index, instead of zipping by ELF byte offset against positional ordering. Robust against aya inlining .text subroutines after the xdp program (which invalidates the previous offset-sorted assumption). - collect_kfunc_offsets: returns Vec<(section_name, offset, name)> across all code sections for diagnostic logging. Verified against relay_xdp_rust.o: .rel.text contains 3 bpf_relay_sha256 relocations (0x18 + 0xb0 in verify_ping_token, 0x128 in verify_session_header), all of which are now patched. Binary builds and clippy clean for relay-xdp. Pre-existing relay-backend warnings unrelated.
1 parent c07a9d4 commit 6d5e323

2 files changed

Lines changed: 361 additions & 252 deletions

File tree

relay-xdp/src/bpf.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,18 @@ impl BpfContext {
105105
let elf_bytes = std::fs::read(xdp_obj_path)
106106
.with_context(|| format!("failed to read BPF ELF from {}", xdp_obj_path.display()))?;
107107

108-
// --- Step 2: Collect kfunc offsets and patch ELF (src_reg 1->2) ---
109-
let kfunc_offsets = collect_kfunc_offsets(&elf_bytes, RELAY_MODULE_KFUNCS)
108+
// --- Step 2: Patch kfunc call sites in all code sections (xdp + .text*) ---
109+
// src_reg 1 -> 2 and encode kfunc index in imm. Walks .relxdp + .rel.text*
110+
// because BPF subroutines marked #[inline(never)] (e.g. verify_ping_token)
111+
// live in .text and contain kfunc calls of their own.
112+
let kfunc_sites = collect_kfunc_offsets(&elf_bytes, RELAY_MODULE_KFUNCS)
110113
.context("failed to collect kfunc offsets from ELF")?;
111114
info!(
112115
"Found {} kfunc call sites in ELF for {:?}",
113-
kfunc_offsets.len(),
116+
kfunc_sites.len(),
114117
RELAY_MODULE_KFUNCS
115118
);
116-
117-
let patched_v1 = patch_elf_skip_kfuncs(&elf_bytes, &kfunc_offsets)
119+
let patched_v1 = patch_elf_skip_kfuncs(&elf_bytes, RELAY_MODULE_KFUNCS)
118120
.context("failed to patch kfunc src_reg in ELF")?;
119121

120122
// --- Step 2b: Patch standard BPF helper calls (src_reg 1->0, imm -> helper ID) ---
@@ -154,11 +156,13 @@ impl BpfContext {
154156
info!("BTF type IDs: {:?}", btf_ids);
155157

156158
// --- Step 8: Patch kfunc instructions with BTF IDs ---
159+
// Identifies each src_reg=2 call by reading the kfunc index encoded in
160+
// imm during step 2 - robust against aya's relocation reordering.
157161
patch_kfunc_instructions(
158162
&mut insns,
159-
&kfunc_offsets,
163+
RELAY_MODULE_KFUNCS,
160164
&btf_ids,
161-
1, // fd_array index 1: kernel uses fd_array[off-1] = fd_array[0] = btf_fd
165+
1, // fd_array index 1: kernel reads fd_array[off] = fd_array[1] = btf_fd
162166
)
163167
.context("failed to patch kfunc instructions")?;
164168

0 commit comments

Comments
 (0)