From nobody Sat Jun 13 22:19:33 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 F339941B35F; Tue, 5 May 2026 10:55:56 +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=1777978558; cv=none; b=rIYnAmQ6KD7DRbYDX4IYkxPIOVX6K9Dd110vJNsjGPph2GaOUVipO6k+pN41OwdDRIjmx+mHNVCPtEf6nl547LN/2KL5ZSPfXL3cIYbz43QYI3nJPIiALP3+AQsdAljOaNP/vgW1j8oWO51puVD/BGFbI2vYL6jLcT7uzj7UGAY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777978558; c=relaxed/simple; bh=GNpPL/wXu6M/XWPH/GuBlcakNFCC+7gVMFuQ+t9skfE=; h=Date:From:To:Subject:Cc:MIME-Version:Message-ID:Content-Type; b=oYgD+ybiXBP4LEs9Em2KIypixJ4Ehom0PCnWqbYVoG89NCd0zrgPFOpXwaE9Dxlj+LLGHBXNFx98xP5KEYxsKu6RJs0+GP9R0nq3IJ8nfY4Mlu/zyTbRYp4/FHQCl4mnupk+lM+iyIVGiamlpiSblAZCB7FYTsW6MorMW8EZTX0= 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=XjHM/T3U; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=UW9Yyzki; 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="XjHM/T3U"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="UW9Yyzki" Date: Tue, 05 May 2026 10:55:54 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1777978555; 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=lrSekKAdjSh4kkrWBUA42OGGGNi/UJbx5pkCQEOOd8E=; b=XjHM/T3UOTI32zrGoiap75LTIwfSFjb7q04SM3q6pd0WLBrHTWf+waAooRRiCOdvEIwDyr nP+uBe5pBLFiJD0yi9NMx8VdsVho485dLEwdBRQBuHCxoz+dEiSUh6ItregQm1qIEYV1Va qLQr+f9BfvLmX7lNhi1y0hRCxoNyWDtdaHPKkAQFVvlbqlO3n4cSNeBiwZvPjEby/i3rBH Az2Q/6Q7a0/EkuIly1rdpF/zXuUbeTcZhKwVg5Pr6AUX7BCJfw9P43wVu4BzYCOeI/oZkn Cwx5hh0z3aoMmOk3qqU5VwTBqxxLtVs/Uzt4qePFPp0Yz2a4ocNcHnBN0jTpWQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1777978555; 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=lrSekKAdjSh4kkrWBUA42OGGGNi/UJbx5pkCQEOOd8E=; b=UW9YyzkiIQda9EaNNxN+mq3nkqCKDaEWvh1iWhIPx7GFhgpZoj+AevJPC+TZybfB+GuwCT 5Zom3uUoEco401Cw== 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: Grow __cfi_* prefix symbols for all CFI+CALL_PADDING Cc: Peter Zijlstra , 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: <177797855430.424702.13725770034437914638.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: fc0bb9915bce0c333f918ca76958d804ccd79f89 Gitweb: https://git.kernel.org/tip/fc0bb9915bce0c333f918ca76958d804c= cd79f89 Author: Josh Poimboeuf AuthorDate: Thu, 23 Apr 2026 15:53:17 -07:00 Committer: Josh Poimboeuf CommitterDate: Mon, 04 May 2026 21:16:07 -07:00 objtool: Grow __cfi_* prefix symbols for all CFI+CALL_PADDING For all CONFIG_CFI+CONFIG_CALL_PADDING configs, for C functions, the __cfi_ symbols only cover the 5-byte kCFI type hash. After that there also N bytes of NOP padding between the hash and the function entry which aren't associated with any symbol. The NOPs can be replaced with actual code at runtime. Without a symbol, unwinders and tooling have no way of knowing where those bytes belong. Grow the existing __cfi_* symbols to fill that gap. Note that assembly functions with SYM_TYPED_FUNC_START() aren't affected by this issue, their __cfi_ symbols also cover the padding. Also, CONFIG_PREFIX_SYMBOLS has no reason to exist: CONFIG_CALL_PADDING is what causes the compiler to emit NOP padding before function entry (via -fpatchable-function-entry), so it's the right condition for creating prefix symbols. Remove CONFIG_PREFIX_SYMBOLS, as it's no longer needed. Simplify the LONGEST_SYM_KUNIT_TEST dependency accordingly. Rework objtool's arguments a bit to handle the variety of prefix/cfi-related cases. Suggested-by: Peter Zijlstra Signed-off-by: Josh Poimboeuf --- arch/x86/Kconfig | 4 +-- lib/Kconfig.debug | 2 +- scripts/Makefile.lib | 7 ++- tools/objtool/builtin-check.c | 15 ++++++- tools/objtool/check.c | 49 +++++++++++++++++++----- tools/objtool/elf.c | 20 ++++++++++- tools/objtool/include/objtool/builtin.h | 7 +-- tools/objtool/include/objtool/elf.h | 1 +- 8 files changed, 84 insertions(+), 21 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f3f7cb0..3eb3c48 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2437,10 +2437,6 @@ config CALL_THUNKS def_bool n select CALL_PADDING =20 -config PREFIX_SYMBOLS - def_bool y - depends on CALL_PADDING && !CFI - menuconfig CPU_MITIGATIONS bool "Mitigations for CPU vulnerabilities" default y diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8ff5adc..4f7496b 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -3070,7 +3070,7 @@ config FORTIFY_KUNIT_TEST config LONGEST_SYM_KUNIT_TEST tristate "Test the longest symbol possible" if !KUNIT_ALL_TESTS depends on KUNIT && KPROBES - depends on !PREFIX_SYMBOLS && !CFI && !GCOV_KERNEL + depends on !CALL_PADDING && !CFI && !GCOV_KERNEL default KUNIT_ALL_TESTS help Tests the longest symbol possible diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 0718e39..7e216d8 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -187,7 +187,11 @@ objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK) +=3D --ha= cks=3Djump_label objtool-args-$(CONFIG_HAVE_NOINSTR_HACK) +=3D --hacks=3Dnoinstr objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) +=3D --hacks=3Dskyla= ke objtool-args-$(CONFIG_X86_KERNEL_IBT) +=3D --ibt -objtool-args-$(CONFIG_FINEIBT) +=3D --cfi +objtool-args-$(CONFIG_CALL_PADDING) +=3D --prefix=3D$(CONFIG_FUNCTION_PA= DDING_BYTES) +ifdef CONFIG_CALL_PADDING +objtool-args-$(CONFIG_CFI) +=3D --cfi +objtool-args-$(CONFIG_FINEIBT) +=3D --fineibt +endif objtool-args-$(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL) +=3D --mcount ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL objtool-args-$(CONFIG_HAVE_OBJTOOL_NOP_MCOUNT) +=3D --mnop @@ -200,7 +204,6 @@ objtool-args-$(CONFIG_STACK_VALIDATION) +=3D --stackv= al objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) +=3D --static-call objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) +=3D --uaccess objtool-args-$(or $(CONFIG_GCOV_KERNEL),$(CONFIG_KCOV)) +=3D --no-unreacha= ble -objtool-args-$(CONFIG_PREFIX_SYMBOLS) +=3D --prefix=3D$(CONFIG_FUNCTION_= PADDING_BYTES) objtool-args-$(CONFIG_OBJTOOL_WERROR) +=3D --werror =20 objtool-args =3D $(objtool-args-y) \ diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index ec7f10a..118c3de 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -73,7 +73,6 @@ static int parse_hacks(const struct option *opt, const ch= ar *str, int unset) =20 static const struct option check_options[] =3D { OPT_GROUP("Actions:"), - OPT_BOOLEAN(0, "cfi", &opts.cfi, "annotate kernel control flow integrit= y (kCFI) function preambles"), OPT_STRING_OPTARG('d', "disas", &opts.disas, "function-pattern", "disass= emble functions", "*"), OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake= ", "patch toolchain bugs/limitations", parse_hacks), OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), @@ -84,7 +83,7 @@ static const struct option check_options[] =3D { OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate re= tpoline usage"), OPT_BOOLEAN(0, "rethunk", &opts.rethunk, "validate and annotate rethunk= usage"), OPT_BOOLEAN(0, "unret", &opts.unret, "validate entry unret placement"), - OPT_INTEGER(0, "prefix", &opts.prefix, "generate prefix symbols"), + OPT_INTEGER(0, "prefix", &opts.prefix, "generate or grow prefix symbols= for N-byte function padding"), OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation m= itigations"), OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rul= es"), OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static call= s"), @@ -92,6 +91,8 @@ static const struct option check_options[] =3D { OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse= _dump), =20 OPT_GROUP("Options:"), + OPT_BOOLEAN(0, "cfi", &opts.cfi, "grow kCFI preamble symbols (use with = --prefix)"), + OPT_BOOLEAN(0, "fineibt", &opts.fineibt, "create .cfi_sites section for= FineIBT"), OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), OPT_BOOLEAN(0, "backup", &opts.backup, "create backup (.orig) file on w= arning/error"), OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"), @@ -163,6 +164,16 @@ static bool opts_valid(void) return false; } =20 + if (opts.cfi && !opts.prefix) { + ERROR("--cfi requires --prefix"); + return false; + } + + if (opts.fineibt && !opts.cfi) { + ERROR("--fineibt requires --cfi"); + return false; + } + if (opts.disas || opts.hack_jump_label || opts.hack_noinstr || diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 4242582..73e99bd 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -881,6 +881,31 @@ static int create_ibt_endbr_seal_sections(struct objto= ol_file *file) return 0; } =20 +/* +* Grow __cfi_ symbols to fill the NOP gap between the 'mov , %rax' a= nd +* the start of the function. +*/ +static int grow_cfi_symbols(struct objtool_file *file) +{ + struct symbol *sym; + + for_each_sym(file->elf, sym) { + if (!is_func_sym(sym) || !strstarts(sym->name, "__cfi_") || + sym->len !=3D 5) + continue; + + if (!find_func_by_offset(sym->sec, sym->offset + sym->len + opts.prefix)) + continue; + + sym->len +=3D opts.prefix; + sym->sym.st_size =3D sym->len; + if (elf_write_symbol(file->elf, sym)) + return -1; + } + + return 0; +} + static int create_cfi_sections(struct objtool_file *file) { struct section *sec; @@ -4903,12 +4928,6 @@ int check(struct objtool_file *file) goto out; } =20 - if (opts.cfi) { - ret =3D create_cfi_sections(file); - if (ret) - goto out; - } - if (opts.rethunk) { ret =3D create_return_sites_sections(file); if (ret) @@ -4928,9 +4947,21 @@ int check(struct objtool_file *file) } =20 if (opts.prefix) { - ret =3D create_prefix_symbols(file); - if (ret) - goto out; + if (!opts.cfi) { + ret =3D create_prefix_symbols(file); + if (ret) + goto out; + } else { + ret =3D grow_cfi_symbols(file); + if (ret) + goto out; + + if (opts.fineibt) { + ret =3D create_cfi_sections(file); + if (ret) + goto out; + } + } } =20 if (opts.ibt) { diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index d9cee8d..33c95a7 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -997,6 +997,26 @@ non_local: return sym; } =20 +int elf_write_symbol(struct elf *elf, struct symbol *sym) +{ + struct section *symtab, *symtab_shndx; + + symtab =3D find_section_by_name(elf, ".symtab"); + if (!symtab) { + ERROR("no .symtab"); + return -1; + } + + symtab_shndx =3D find_section_by_name(elf, ".symtab_shndx"); + + if (elf_update_symbol(elf, symtab, symtab_shndx, sym)) + return -1; + + mark_sec_changed(elf, symtab, true); + + return 0; +} + struct symbol *elf_create_section_symbol(struct elf *elf, struct section *= sec) { struct symbol *sym =3D calloc(1, sizeof(*sym)); diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/includ= e/objtool/builtin.h index b9e229e..e844e9c 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -9,8 +9,8 @@ =20 struct opts { /* actions: */ - bool cfi; bool checksum; + const char *disas; bool dump_orc; bool hack_jump_label; bool hack_noinstr; @@ -20,6 +20,7 @@ struct opts { bool noabs; bool noinstr; bool orc; + int prefix; bool retpoline; bool rethunk; bool unret; @@ -27,14 +28,14 @@ struct opts { bool stackval; bool static_call; bool uaccess; - int prefix; - const char *disas; =20 /* options: */ bool backtrace; bool backup; + bool cfi; const char *debug_checksum; bool dryrun; + bool fineibt; bool link; bool mnop; bool module; diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index e452784..305183f 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -199,6 +199,7 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, = struct section *sec, struct symbol *sym, s64 addend); =20 +int elf_write_symbol(struct elf *elf, struct symbol *sym); int elf_write_insn(struct elf *elf, struct section *sec, unsigned long off= set, unsigned int len, const char *insn); =20