From nobody Sat Jun 13 22:04:00 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63AC04219F9; Tue, 5 May 2026 10:55:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777978562; cv=none; b=JLRd5i76yH2dTC6NDlN3kGA+6ALyPqfv9+ifSXVlicgqZoryiy2ghyLcZeEEFqOfRRVy6VgoCxaw0plARv42hY7DyWWMJ6Cefyqe0ibqGmk1n3S6Ti2IwfzCWxA6/lw1mtm+pNjuHWVPbqmbCH//ut+cwFbkIqlVmXqMTk5JMSo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777978562; c=relaxed/simple; bh=iFTfxLPKAkAB2eZmDjlAI5VQ7qnYNfytHODDBSfSujg=; h=Date:From:To:Subject:Cc:MIME-Version:Message-ID:Content-Type; b=Xnl7p/f43ciSSxQDO2rkyHnP62jKEqfQ3eRzq5HCUix0jAv/5RKYNa6TqBGSu/lmGac2pdtW2DG/7L8teZBkAHjMEEjtvvDbnoslVgNhNmxBzrqBo4CGdLGzTnDPRn/9nvhlikYvQFOcUmn9Fx5QARoNY78WugSfU1jo+WYm5b4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=SjgiweXu; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=I+FrTtaC; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="SjgiweXu"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="I+FrTtaC" Date: Tue, 05 May 2026 10:55:55 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1777978556; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=qIjDVbKpr6Ns42rEn0f2+/BzvRcZOC11uPLUaCwUGXs=; b=SjgiweXuLHtFzFy+pnTarvGhs58arFh9yCQOsvrwrAX/qLNwJDvXeDoyRKAAaRzZDxbXuK ukBE3MfULe1IwSO1hJ0Zy9UDYQFWVy/GQeU0kYeg1VbVGbrSJJtjX/uz/iyVQxPllOVC3Z HLnd2AliWJgaUuYlJSO6qHEs4n5Qn/H+oGIQyB6dHaxMHIjJQrlOTIgM+J8YpS6nSi9r4j Bb599Xv3OXk2L61KqjXxgnR6HJmDWslEzuPuNIzDLSwWPGSggByMAu6lsCDh/WGb1WwQO4 Zs9TFMdLauOjqs+ZYgstHyMpszn3iUdJcAFPlBBzDQPMt0rHPeDRxbunQR4Liw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1777978556; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=qIjDVbKpr6Ns42rEn0f2+/BzvRcZOC11uPLUaCwUGXs=; b=I+FrTtaCJzSX/LQR7IMnF+5wn2HhsK9ZZtkxFBrBMdTA9fP93Gw97skvWlE64pRBb3vNC1 naEhqYO8ikoffcBA== From: "tip-bot2 for Josh Poimboeuf" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: objtool/core] objtool/klp: Fix position-dependent checksums for non-relocated jumps/calls Cc: Song Liu , Josh Poimboeuf , x86@kernel.org, linux-kernel@vger.kernel.org Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <177797855550.424702.3889127559386854532.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Precedence: bulk Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The following commit has been merged into the objtool/core branch of tip: Commit-ID: cca84cb12908f1cfcecaef80a7692017e2d6a945 Gitweb: https://git.kernel.org/tip/cca84cb12908f1cfcecaef80a7692017e= 2d6a945 Author: Josh Poimboeuf AuthorDate: Fri, 03 Apr 2026 11:57:02 -07:00 Committer: Josh Poimboeuf CommitterDate: Mon, 04 May 2026 21:16:06 -07:00 objtool/klp: Fix position-dependent checksums for non-relocated jumps/calls When computing klp checksums, instructions with non-relocated jump/call destination offsets are problematic because the offset values can change when surrounding code has moved, causing the function to be incorrectly marked as changed. Specifically, that includes jumps from alternatives to the end of the alternative, which from objtool's perspective are jumps to the end of the alternative instruction block in the original function. Note that 'jump_dest' jumps don't include sibling calls (those use call_dest), nor do they include jumps to/from .cold sub functions (those are cross-section and need a reloc). Fix it by hashing the opcode bytes (excluding the immediate operand) along with a position-independent representation of the destination. For calls, use the function name, and for jumps, use the destination's offset within its function. [Note the "9 bit hole" comment was wrong: it has been 8 bits since commit 70589843b36f ("objtool: Add option to trace function validation") added the 'trace' field. Adding the 4-bit 'immediate_len' field now leaves a 4-bit hole.] Fixes: 0d83da43b1e1 ("objtool/klp: Add --checksum option to generate per-fu= nction checksums") Acked-by: Song Liu Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/x86/decode.c | 17 +++++++- tools/objtool/include/objtool/arch.h | 3 +- tools/objtool/include/objtool/check.h | 3 +- tools/objtool/klp-checksum.c | 53 +++++++++++++++++++++++--- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decod= e.c index 350b8ee..1b387d5 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -805,14 +805,27 @@ int arch_decode_instruction(struct objtool_file *file= , const struct section *sec break; } =20 - if (ins.immediate.nbytes) + if (ins.immediate.nbytes) { insn->immediate =3D ins.immediate.value; - else if (ins.displacement.nbytes) + insn->immediate_len =3D ins.immediate.nbytes; + } else if (ins.displacement.nbytes) { insn->immediate =3D ins.displacement.value; + insn->immediate_len =3D ins.displacement.nbytes; + } =20 return 0; } =20 +size_t arch_jump_opcode_bytes(struct objtool_file *file, struct instructio= n *insn, + unsigned char *buf) +{ + size_t len; + + len =3D insn->len - insn->immediate_len; + memcpy(buf, insn->sec->data->d_buf + insn->offset, len); + return len; +} + void arch_initial_func_cfi_state(struct cfi_init_state *state) { int i; diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/o= bjtool/arch.h index 8866158..96d828a 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -79,6 +79,9 @@ int arch_decode_instruction(struct objtool_file *file, co= nst struct section *sec unsigned long offset, unsigned int maxlen, struct instruction *insn); =20 +size_t arch_jump_opcode_bytes(struct objtool_file *file, struct instructio= n *insn, + unsigned char *buf); + bool arch_callee_saved_reg(unsigned char reg); =20 unsigned long arch_jump_destination(struct instruction *insn); diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/= objtool/check.h index fe08205..063f598 100644 --- a/tools/objtool/include/objtool/check.h +++ b/tools/objtool/include/objtool/check.h @@ -68,6 +68,7 @@ struct instruction { s8 instr; =20 u32 idx : INSN_CHUNK_BITS, + immediate_len : 4, dead_end : 1, ignore_alts : 1, hint : 1, @@ -81,7 +82,7 @@ struct instruction { hole : 1, fake : 1, trace : 1; - /* 9 bit hole */ + /* 4 bit hole */ =20 struct alt_group *alt_group; struct instruction *jump_dest; diff --git a/tools/objtool/klp-checksum.c b/tools/objtool/klp-checksum.c index 19653db..b8e47f2 100644 --- a/tools/objtool/klp-checksum.c +++ b/tools/objtool/klp-checksum.c @@ -66,17 +66,58 @@ static void checksum_update_insn(struct objtool_file *f= ile, struct symbol *func, if (insn->fake) return; =20 - __checksum_update_insn(func, insn, insn->sec->data->d_buf + insn->offset,= insn->len); - if (!reloc) { struct symbol *call_dest =3D insn_call_dest(insn); + struct instruction *jump_dest =3D insn->jump_dest; =20 - if (call_dest) - __checksum_update_insn(func, insn, call_dest->demangled_name, - strlen(call_dest->demangled_name)); - goto alts; + /* + * For a jump/call non-relocated dest offset embedded in the + * instruction, the offset may vary due to changes in + * surrounding code. Just hash the opcode and a + * position-independent representation of the destination. + */ + + if (call_dest || jump_dest) { + unsigned char buf[16]; + size_t len; + + len =3D arch_jump_opcode_bytes(file, insn, buf); + __checksum_update_insn(func, insn, buf, len); + + if (call_dest) { + __checksum_update_insn(func, insn, call_dest->demangled_name, + strlen(call_dest->demangled_name)); + + } else if (jump_dest) { + struct symbol *dest_sym; + unsigned long offset; + + /* + * use insn->_sym instead of insn_sym() here. + * For alternative replacements, the latter + * would give the function of the code being + * replaced. + */ + dest_sym =3D jump_dest->_sym; + if (!dest_sym) + goto alts; + + __checksum_update_insn(func, insn, dest_sym->demangled_name, + strlen(dest_sym->demangled_name)); + + offset =3D jump_dest->offset - dest_sym->offset; + __checksum_update_insn(func, insn, &offset, sizeof(offset)); + } + + goto alts; + } } =20 + __checksum_update_insn(func, insn, insn->sec->data->d_buf + insn->offset,= insn->len); + + if (!reloc) + goto alts; + sym =3D reloc->sym; offset =3D arch_insn_adjusted_addend(insn, reloc); =20