Skip to content

"bpf, arm64: Reject out-of-range B.cond targets" on 6.1#8

Open
shunghsiyu wants to merge 1 commit into
kernel-patches:linux-6.1.yfrom
shunghsiyu:linux-6.1.y
Open

"bpf, arm64: Reject out-of-range B.cond targets" on 6.1#8
shunghsiyu wants to merge 1 commit into
kernel-patches:linux-6.1.yfrom
shunghsiyu:linux-6.1.y

Conversation

@shunghsiyu

Copy link
Copy Markdown
Collaborator

commit 48d83d9 upstream.

aarch64_insn_gen_cond_branch_imm() calls label_imm_common() to compute a 19-bit signed byte offset for a conditional branch, but unlike its siblings aarch64_insn_gen_branch_imm() and aarch64_insn_gen_comp_branch_imm(), it does not check whether label_imm_common() returned its out-of-range sentinel (range) before feeding the value to aarch64_insn_encode_immediate().

aarch64_insn_encode_immediate() unconditionally masks the value with the 19-bit field mask, so an offset that was rejected by label_imm_common() gets silently truncated. With the sentinel value SZ_1M, the resulting field ends up with bit 18 (the sign bit of the 19-bit signed displacement) set, and the CPU decodes it as a ~1 MiB backward branch, producing an incorrectly targeted B.cond instruction. For code-gen locations like the emit_bpf_tail_call() this function is the only barrier between an overflowing displacement and a silently miscompiled branch.

Fix it by returning AARCH64_BREAK_FAULT when the offset is out of range, so callers see a loud failure instead of a silently misencoded branch. validate_code() scans the generated image for any AARCH64_BREAK_FAULT and then lets the JIT fail.

Fixes: 345e0d3 ("arm64: introduce aarch64_insn_gen_cond_branch_imm()")
Fixes: c94ae4f ("arm64: insn: remove BUG_ON from codegen")

Reviewed-by: Puranjay Mohan puranjay@kernel.org
Link: https://lore.kernel.org/r/20260415121403.639619-1-daniel@iogearbox.net

commit 48d83d9 upstream.

aarch64_insn_gen_cond_branch_imm() calls label_imm_common() to
compute a 19-bit signed byte offset for a conditional branch,
but unlike its siblings aarch64_insn_gen_branch_imm() and
aarch64_insn_gen_comp_branch_imm(), it does not check whether
label_imm_common() returned its out-of-range sentinel (range)
before feeding the value to aarch64_insn_encode_immediate().

aarch64_insn_encode_immediate() unconditionally masks the value
with the 19-bit field mask, so an offset that was rejected by
label_imm_common() gets silently truncated. With the sentinel
value SZ_1M, the resulting field ends up with bit 18 (the sign
bit of the 19-bit signed displacement) set, and the CPU decodes
it as a ~1 MiB *backward* branch, producing an incorrectly
targeted B.cond instruction. For code-gen locations like the
emit_bpf_tail_call() this function is the only barrier between
an overflowing displacement and a silently miscompiled branch.

Fix it by returning AARCH64_BREAK_FAULT when the offset is out
of range, so callers see a loud failure instead of a silently
misencoded branch. validate_code() scans the generated image
for any AARCH64_BREAK_FAULT and then lets the JIT fail.

Fixes: 345e0d3 ("arm64: introduce aarch64_insn_gen_cond_branch_imm()")
Fixes: c94ae4f ("arm64: insn: remove BUG_ON from codegen")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Puranjay Mohan <puranjay@kernel.org>
Link: https://lore.kernel.org/r/20260415121403.639619-1-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
@kernel-patches-daemon-bpf kernel-patches-daemon-bpf Bot force-pushed the linux-6.1.y branch 8 times, most recently from bbd96dd to a8318e8 Compare July 9, 2026 20:55
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.

2 participants