From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Sashiko <sashiko-bot@kernel.org>,
Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Eduard Zingerman <eddyz87@gmail.com>,
Emil Tsalapatis <emil@etsalapatis.com>,
Nicholas Carlini <npc@anthropic.com>,
kkd@meta.com, kernel-team@meta.com
Subject: [PATCH bpf v4 10/11] libbpf: Reject truncated ldimm64 CO-RE relocations
Date: Tue, 15 Sep 2026 00:25:07 +0200 [thread overview]
Message-ID: <20260914222514.1635018-11-memxor@gmail.com> (raw)
In-Reply-To: <20260914222514.1635018-1-memxor@gmail.com>
CO-RE relocation of an ldimm64 instruction operates on two instruction
slots. The original ldimm64 support checked that the second slot existed
only on the resolved relocation path, leaving unresolved relocation
poisoning able to write past the instruction allocation. When CO-RE logic
was moved to the shared relocation implementation, even the resolved-path
check was lost because bpf_core_patch_insn() no longer received the
program length.
A malformed BPF ELF can therefore end a function after the first ldimm64
slot and attach a CO-RE relocation to it. libbpf allocates the instruction
array according to the function symbol size. bpf_core_patch_insn() then
reads the absent second slot while validating a resolved relocation or
writes a poison instruction past the allocation for an unresolved one.
Pass the total instruction count to the shared patch helper and reject a
terminal ldimm64 before either relocation result is handled. Thread the
count through the in-kernel caller as well, since it compiles the same
shared relocation implementation.
Fixes: eacaaed784e2 ("libbpf: Implement enum value-based CO-RE relocations")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://lore.kernel.org/20260914140852.03DA21F0089B@smtp.kernel.org
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
include/linux/bpf.h | 2 +-
kernel/bpf/btf.c | 6 +++---
kernel/bpf/check_btf.c | 2 +-
tools/lib/bpf/libbpf.c | 3 ++-
tools/lib/bpf/relo_core.c | 11 +++++++++--
tools/lib/bpf/relo_core.h | 5 +++--
6 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index e57af902560c..62155d87ce31 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -3196,7 +3196,7 @@ bool btf_type_ids_nocast_alias(struct bpf_verifier_log *log,
const struct btf *arg_btf, u32 arg_id);
int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
- int relo_idx, void *insn);
+ int relo_idx, void *insn, size_t insn_cnt);
static inline bool unprivileged_ebpf_enabled(void)
{
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index d67a169ba2bb..78cd9661cdbd 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -9729,7 +9729,7 @@ bpf_core_find_cands(struct bpf_core_ctx *ctx, u32 local_type_id)
}
int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
- int relo_idx, void *insn)
+ int relo_idx, void *insn, size_t insn_cnt)
{
bool need_cands = relo->kind != BPF_CORE_TYPE_ID_LOCAL;
struct bpf_core_cand_list cands = {};
@@ -9793,8 +9793,8 @@ int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
if (err)
goto out;
- err = bpf_core_patch_insn((void *)ctx->log, insn, relo->insn_off / 8, relo, relo_idx,
- &targ_res);
+ err = bpf_core_patch_insn((void *)ctx->log, insn, insn_cnt, relo->insn_off / 8,
+ relo, relo_idx, &targ_res);
out:
kfree(specs);
diff --git a/kernel/bpf/check_btf.c b/kernel/bpf/check_btf.c
index 4c1ed842f661..63d0375f5bb0 100644
--- a/kernel/bpf/check_btf.c
+++ b/kernel/bpf/check_btf.c
@@ -399,7 +399,7 @@ int bpf_check_core_relo(struct bpf_verifier_env *env,
}
err = bpf_core_apply(&ctx, &core_relo, i,
- &prog->insnsi[core_relo.insn_off / 8]);
+ &prog->insnsi[core_relo.insn_off / 8], prog->len);
if (err)
break;
bpfptr_add(&u_core_relo, rec_size);
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b749c01742ee..619e664f0c00 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -6223,7 +6223,8 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path)
goto out;
}
- err = bpf_core_patch_insn(prog->name, insn, insn_idx, rec, i, &targ_res);
+ err = bpf_core_patch_insn(prog->name, insn, prog->insns_cnt, insn_idx,
+ rec, i, &targ_res);
if (err) {
pr_warn("prog '%s': relo #%d: failed to patch insn #%d: %s\n",
prog->name, i, insn_idx, errstr(err));
diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
index 2672623a4198..92ff923f0d13 100644
--- a/tools/lib/bpf/relo_core.c
+++ b/tools/lib/bpf/relo_core.c
@@ -1046,12 +1046,19 @@ static int insn_bytes_to_bpf_size(__u32 sz)
* 6. *(T *)(rX + <off>) = <imm>, where T is one of {u8, u16, u32, u64}.
*/
int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
- int insn_idx, const struct bpf_core_relo *relo,
- int relo_idx, const struct bpf_core_relo_res *res)
+ size_t insn_cnt, int insn_idx,
+ const struct bpf_core_relo *relo, int relo_idx,
+ const struct bpf_core_relo_res *res)
{
__u64 orig_val, new_val;
__u8 class;
+ if (is_ldimm64_insn(insn) && (size_t)insn_idx + 1 >= insn_cnt) {
+ pr_warn("prog '%s': relo #%d: insn #%d (LDIMM64) is truncated\n",
+ prog_name, relo_idx, insn_idx);
+ return -EINVAL;
+ }
+
class = BPF_CLASS(insn->code);
orig_val = res->orig_val;
diff --git a/tools/lib/bpf/relo_core.h b/tools/lib/bpf/relo_core.h
index 1c0566daf8e8..db2e106dc73d 100644
--- a/tools/lib/bpf/relo_core.h
+++ b/tools/lib/bpf/relo_core.h
@@ -87,8 +87,9 @@ int bpf_core_calc_relo_insn(const char *prog_name,
struct bpf_core_relo_res *targ_res);
int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
- int insn_idx, const struct bpf_core_relo *relo,
- int relo_idx, const struct bpf_core_relo_res *res);
+ size_t insn_cnt, int insn_idx,
+ const struct bpf_core_relo *relo, int relo_idx,
+ const struct bpf_core_relo_res *res);
int bpf_core_parse_spec(const char *prog_name, const struct btf *btf,
const struct bpf_core_relo *relo,
--
2.53.0
next prev parent reply other threads:[~2026-09-14 22:25 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-14 22:24 [PATCH bpf v4 00/11] Misc bug fixes - part 5 Kumar Kartikeya Dwivedi
2026-09-14 22:24 ` [PATCH bpf v4 01/11] bpf: Make post-verification instruction rewrites killable Kumar Kartikeya Dwivedi
2026-09-14 22:24 ` [PATCH bpf v4 02/11] bpf: Preserve packet pointer class displacement in regsafe() Kumar Kartikeya Dwivedi
2026-09-14 22:25 ` [PATCH bpf v4 03/11] selftests/bpf: Test packet pointer class displacement pruning Kumar Kartikeya Dwivedi
2026-09-14 22:25 ` [PATCH bpf v4 04/11] bpf: Apply CO-RE relocations before subprogram validation Kumar Kartikeya Dwivedi
2026-09-14 23:15 ` bot+bpf-ci
2026-09-16 18:22 ` Eduard Zingerman
2026-09-14 22:25 ` [PATCH bpf v4 05/11] selftests/bpf: Test early in-kernel CO-RE relocation Kumar Kartikeya Dwivedi
2026-09-14 23:28 ` bot+bpf-ci
2026-09-16 18:23 ` Eduard Zingerman
2026-09-16 18:26 ` Kumar Kartikeya Dwivedi
2026-09-14 22:25 ` [PATCH bpf v4 06/11] bpf: Restrict CO-RE poisoning to relocatable instructions Kumar Kartikeya Dwivedi
2026-09-14 23:28 ` bot+bpf-ci
2026-09-14 22:25 ` [PATCH bpf v4 07/11] selftests/bpf: Test CO-RE instruction poisoning restrictions Kumar Kartikeya Dwivedi
2026-09-16 18:27 ` Eduard Zingerman
2026-09-14 22:25 ` [PATCH bpf v4 08/11] bpf: Assign lock identity to callback map values Kumar Kartikeya Dwivedi
2026-09-14 22:25 ` [PATCH bpf v4 09/11] selftests/bpf: Check callback map value lock identity Kumar Kartikeya Dwivedi
2026-09-16 19:04 ` Eduard Zingerman
2026-09-14 22:25 ` Kumar Kartikeya Dwivedi [this message]
2026-09-16 18:37 ` [PATCH bpf v4 10/11] libbpf: Reject truncated ldimm64 CO-RE relocations Eduard Zingerman
2026-09-14 22:25 ` [PATCH bpf v4 11/11] selftests/bpf: Add truncated CO-RE ldimm64 test Kumar Kartikeya Dwivedi
2026-09-14 23:15 ` bot+bpf-ci
2026-09-16 18:43 ` Eduard Zingerman
2026-09-16 19:02 ` Kumar Kartikeya Dwivedi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260914222514.1635018-11-memxor@gmail.com \
--to=memxor@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=kernel-team@meta.com \
--cc=kkd@meta.com \
--cc=npc@anthropic.com \
--cc=sashiko-bot@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.