> On Sep 4, 2025, at 20:24, Kees Cook <k...@kernel.org> wrote:
> 
> Implements the Linux Kernel Control Flow Integrity ABI, which provides a
> function prototype based forward edge control flow integrity protection
> by instrumenting every indirect call to check for a hash value before
> the target function address. If the hash at the call site and the hash
> at the target do not match, execution will trap.
> 
> See the start of kcfi.cc for design details.
> 
> gcc/ChangeLog:
> 
> * kcfi.h: New file with KCFI public interface declarations.
> * kcfi.cc: New file implementing Kernel Control Flow Integrity
> infrastructure.
> * Makefile.in (OBJS): Add kcfi.o.
> * flag-types.h (enum sanitize_code): Add SANITIZE_KCFI.
> * gimple.h (enum gf_mask): Add GF_CALL_INLINED_FROM_KCFI_NOSANTIZE.
> (gimple_call_set_inlined_from_kcfi_nosantize): New function.
> (gimple_call_inlined_from_kcfi_nosantize_p): New function.
> * tree-pass.h Add kcfi passes.
> * c-family/c-attribs.cc: Include asan.h.
> (handle_patchable_function_entry_attribute): Add error for using
> patchable_function_entry attribute with -fsanitize=kcfi.
> * df-scan.cc (df_uses_record): Add KCFI case to handle KCFI RTL
> patterns and process wrapped RTL.
> * doc/invoke.texi (fsanitize=kcfi): Add documentation for KCFI
> sanitizer option.
> * doc/tm.texi.in: Add Kernel Control Flow Integrity section with
> TARGET_KCFI_SUPPORTED, TARGET_KCFI_MASK_TYPE_ID,
> TARGET_KCFI_EMIT_TYPE_ID hooks.
> * doc/tm.texi: Regenerate.
> * final.cc (call_from_call_insn): Add KCFI case to handle
> KCFI-wrapped calls.
> * opts.cc (sanitizer_opts): Add kcfi entry.
> * passes.cc: Include kcfi.h.
> * passes.def: Add KCFI passes (GIMPLE and IPA).
> * rtl.def (KCFI): Add new RTL code for KCFI instrumentation.
> * rtlanal.cc (rtx_cost): Add KCFI case.
> * target.def: Add KCFI target hooks.
> * toplev.cc (process_options): Add KCFI option processing.
> * tree-inline.cc: Include kcfi.h and asan.h.
> (copy_bb): Handle KCFI no_sanitize attribute propagation during
> inlining.
> * varasm.cc (assemble_start_function): Emit KCFI preambles.
> (assemble_external_real): Emit KCFI typeid symbols.
> (default_elf_asm_named_section): Handle .kcfi_traps using
> SECTION_LINK_ORDER flag.
> 
> Signed-off-by: Kees Cook <k...@kernel.org>
> ---
> gcc/kcfi.h                |  47 +++
> gcc/kcfi.cc               | 764 ++++++++++++++++++++++++++++++++++++++
> gcc/Makefile.in           |   1 +
> gcc/flag-types.h          |   2 +
> gcc/gimple.h              |  21 ++
> gcc/tree-pass.h           |   3 +
> gcc/c-family/c-attribs.cc |  12 +
> gcc/df-scan.cc            |   6 +
> gcc/doc/invoke.texi       |  35 ++
> gcc/doc/tm.texi           |  31 ++
> gcc/doc/tm.texi.in        |  12 +
> gcc/final.cc              |   3 +
> gcc/opts.cc               |   1 +
> gcc/passes.cc             |   1 +
> gcc/passes.def            |   3 +
> gcc/rtl.def               |   6 +
> gcc/rtlanal.cc            |   5 +
> gcc/target.def            |  38 ++
> gcc/toplev.cc             |  11 +
> gcc/tree-inline.cc        |  10 +
> gcc/varasm.cc             |  46 ++-
> 21 files changed, 1048 insertions(+), 10 deletions(-)
> create mode 100644 gcc/kcfi.h
> create mode 100644 gcc/kcfi.cc
> 
> diff --git a/gcc/kcfi.h b/gcc/kcfi.h
> new file mode 100644
> index 000000000000..17ec59a1a3b8
> --- /dev/null
> +++ b/gcc/kcfi.h
> @@ -0,0 +1,47 @@
> +/* Kernel Control Flow Integrity (KCFI) support for GCC.
> +   Copyright (C) 2025 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_KCFI_H
> +#define GCC_KCFI_H
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "rtl.h"
> +
> +/* Common helper for RTL patterns to emit .kcfi_traps section entry.
> +   Call after emitting trap label and instruction with the trap symbol
> +   reference.  */
> +extern void kcfi_emit_traps_section (FILE *file, rtx trap_label_sym);
> +
> +/* Extract KCFI type ID from current GIMPLE statement.  */
> +extern rtx kcfi_get_call_type_id (void);
> +
> +/* Emit KCFI type ID symbol for address-taken functions.  */
> +extern void emit_kcfi_typeid_symbol (FILE *asm_file, tree decl,
> +     const char *name);
> +
> +/* Emit KCFI preamble.  */
> +extern void kcfi_emit_preamble (FILE *file, tree decl,
> + const char *actual_fname);
> +
> +/* For calculating callsite offset.  */
> +extern HOST_WIDE_INT kcfi_patchable_entry_prefix_nops;
> +
> +#endif /* GCC_KCFI_H */
> diff --git a/gcc/kcfi.cc b/gcc/kcfi.cc
> new file mode 100644
> index 000000000000..1ae0602eac7b
> --- /dev/null
> +++ b/gcc/kcfi.cc
> @@ -0,0 +1,764 @@
> +/* Kernel Control Flow Integrity (KCFI) support for GCC.
> +   Copyright (C) 2025 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +/* KCFI ABI Design:
> +
> +The Linux Kernel Control Flow Integrity ABI provides a function prototype
> +based forward edge control flow integrity protection by instrumenting
> +every indirect call to check for a hash value before the target function
> +address. If the hash at the call site and the hash at the target do not
> +match, execution will trap.
> +
> +The general CFI ideas are discussed here, but focuses more on a CFG
> +analysis to construct valid call destinations, which tends to require LTO:
> +https://users.soe.ucsc.edu/~abadi/Papers/cfi-tissec-revised.pdf
> +
> +Later refinement for using jump tables (constructed via CFG analysis
> +during LTO) was proposed here:
> +https://www.usenix.org/system/files/conference/usenixsecurity14/sec14-paper-tice.pdf
> +
> +Linux used the above implementation from 2018 to 2022:
> +https://android-developers.googleblog.com/2018/10/control-flow-integrity-in-android-kernel.html
> +but the corner cases for target addresses not being the actual functions
> +(i.e. pointing into the jump table) was a continual source of problems,
> +and generating the jump tables required full LTO, which had its own set
> +of problems.
> +
> +Looking at function prototypes as the source of call validity was
> +presented here, though still relied on LTO:
> +https://www.blackhat.com/docs/asia-17/materials/asia-17-Moreira-Drop-The-Rop-Fine-Grained-Control-Flow-Integrity-For-The-Linux-Kernel-wp.pdf
> +
> +The KCFI approach built on the function-prototype idea, but avoided
> +needing LTO, and could be further updated to deal with CPU errata
> +(retpolines, etc):
> +https://lpc.events/event/16/contributions/1315/
> +
> +KCFI has a number of specific constraints. Some are tied to the
> +backend architecture, which are covered in arch-specific code.
> +The constraints are:
> +
> +- The KCFI scheme generates a unique 32-bit hash for each unique function
> +  prototype, allowing for indirect call sites to verify that they are
> +  calling into a matching _type_ of function pointer. This changes the
> +  semantics of some optimization logic because now indirect calls to
> +  different types cannot be merged. For example:
> +
> +    if (p->func_type_1)
> + return p->func_type_1();
> +    if (p->func_type_2)
> + return p->func_type_2();
> +
> +  In final asm, the optimizer may collapse the second indirect call
> +  into a jump to the first indirect call once it has loaded the function
> +  pointer. KCFI must block cross-type merging otherwise there will be a
> +  single KCFI check happening for only 1 type but being used by 2 target
> +  types. The distinguishing characteristic for call merging becomes the
> +  type, not the address/register usage.
> +
> +- The check-call instruction sequence must be treated a single unit: it
> +  cannot be rearranged or split or optimized. The pattern is that
> +  indirect calls, "call *$target", get converted into:
> +
> +    mov $target_expression, %target ; only present if the expression was
> +                                    ; not already %target register
> +    load -$offset(%target), %tmp    ; load the typeid hash at target
> +    cmp $hash, %tmp                 ; compare expected typeid with loaded
> +    je .Lcheck_passed               ; jump to the indirect call
> +  .Lkcfi_trap$N:                    ; label of trap insn
> +    trap                            ; trap on failure, but arranged so
> +                                    ; "permissive mode" falls through
> +  .Lkcfi_call$N:                    ; label of call insn
> +    call *%target                   ; actual indirect call
> +
> +  This pattern of call immediately after trap provides for the
> +  "permissive" checking mode automatically: the trap gets handled,
> +  a warning emitted, and then execution continues after the trap to
> +  the call.
> +
> +- KCFI check-call instrumentation must survive tail call optimization.
> +  If an indirect call is turned into an indirect jump, KCFI checking
> +  must still happen (but will still use the jmp).
> +
> +- Functions that may be called indirectly have a preamble added,
> +  __cfi_$original_func_name, which contains the $hash value:
> +
> +    __cfi_target_func:
> +      .word $hash
> +    target_func:
> +       [regular function entry...]
> +
> +- The preamble needs to interact with patchable function entry so that
> +  the hash appears further away from the actual start of the function
> +  (leaving the prefix NOPs of the patchable function entry unchanged).
> +  This means only _globally defined_ patchable function entry is supported
> +  with KCFI (indrect call sites must know in advance what the offset is,
> +  which may not be possible with extern functions). For example, a "4,4"
> +  patchable function entry would end up like:
> +
> +    __cfi_target_func:
> +      .data $hash
> +      nop nop nop nop
> +    target_func:
> +       [regular function entry...]
> +
> +  Architectures may need to add alignment nops prior to the hash to keep 
> things
> +  aligned for function call conventions.
> +
> +- External functions that are address-taken have a weak 
> __kcfi_typeid_$funcname
> +  symbol added with the hash value available so that the hash can be 
> referenced
> +  from assembly linkages, etc, where the hash values cannot be calculated 
> (i.e
> +  where C type information is missing):
> +
> +    .weak   __kcfi_typeid_$func
> +    .set    __kcfi_typeid_$func, $hash
> +
> +- On architectures that do not have a good way to encode additional
> +  details in their trap insn (e.g. x86_64 and riscv64), the trap location
> +  is identified as a KCFI trap via a relative address offset entry
> +  emitted into the .kcfi_traps section for each indirect call site's
> +  trap instruction. The previous check-call example's insn sequence has
> +  a section push/pop inserted between the trap and call:
> +
> +  ...
> +  .Lkcfi_trap$N:
> +    trap
> +  .section .kcfi_traps,"ao",@progbits,.text
> +    .Lkcfi_entry$N:
> +        .long .Lkcfi_trap$N - .Lkcfi_entry$N
> +  .text
> +  .Lkcfi_call$N:
> +    call *%target
> +
> +  For architectures that can encode immediates in their trap function
> +  (e.g. aarch64 and arm32), this isn't needed: they just use immediate
> +  codes that indicate a KCFI trap.
> +
> +- The no_sanitize("kcfi") function attribute means that the marked
> +  function must not produce KCFI checking for indirect calls, and this
> +  attribute must survive inlining. This is used rarely by Linux, but
> +  is required to make BPF JIT trampolines work on older Linux kernel
> +  versions.
> +
> +As a result of these constraints, there are some behavioral aspects
> +that need to be preserved across the middle-end and back-end.
> +
> +For indirect call sites:
> +
> +- Keeping indirect calls from being merged (see above) by adding a
> +  wrapping type so that equality was tested based on type-id.

I still think that the additional new created wrapping type and the new 
assignment stmt

wrapper_tmp = (wrapper_ptr_type) fn
is not necessary.

All the information can be get from function type + type-id which is attached 
as an attribute
to the original_function_type of “fn”. 
Could you explain why the wrapper type and the new temporary, new assignment is 
necessary?

> +
> +- Keeping typeid information available through to the RTL expansion
> +  phase was done via a new KCFI insn that wraps CALL and the typeid.

Is the new KCFI insn the following:
wrapper_tmp = (wrapper_ptr_type) fn?

Why the type-id attached as the attribute is not enough? 
> +
> +- To make sure KCFI expansion is skipped for inline functions, the
> +  inlining is marked during GIMPLE with a new flag which is checked
> +  during expansion.
> +
> +For indirect call targets:
> +
> +- kcfi_emit_preamble() uses function_needs_kcfi_preamble(),
> +  to emit the preablem,
Typo: preamble. 

> which interacts with patchable function
> +  entry to add any needed alignment.
> +
> +- gcc/varasm.cc, assemble_external_real() calls emit_kcfi_typeid_symbol()
> +  to add the __kcfi_typeid symbols (see get_function_kcfi_type_id()
> +  below).
> +
> +*/
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "target.h"
> +#include "function.h"
> +#include "tree.h"
> +#include "tree-pass.h"
> +#include "dumpfile.h"
> +#include "basic-block.h"
> +#include "gimple.h"
> +#include "gimple-iterator.h"
> +#include "cgraph.h"
> +#include "kcfi.h"
> +#include "stringpool.h"
> +#include "attribs.h"
> +#include "rtl.h"
> +#include "cfg.h"
> +#include "cfgrtl.h"
> +#include "asan.h"
> +#include "diagnostic-core.h"
> +#include "memmodel.h"
> +#include "print-tree.h"
> +#include "emit-rtl.h"
> +#include "output.h"
> +#include "builtins.h"
> +#include "varasm.h"
> +#include "opts.h"
> +#include "mangle.h"
> +#include "target.h"
> +#include "flags.h"
> +
> +HOST_WIDE_INT kcfi_patchable_entry_prefix_nops = 0;  /* For callsite offset 
> */
> +static HOST_WIDE_INT kcfi_patchable_entry_arch_alignment_nops = 0;  /* For 
> preamble alignment */
> +
> +/* Common helper for RTL patterns to emit .kcfi_traps section entry.  */

there should be one empty line between the comments of the function and the 
start of the function. 
I noticed that you need such empty line for all the new functions you added.  
-:)

> +void
> +kcfi_emit_traps_section (FILE *file, rtx trap_label_sym)
> +{
> +  /* Generate entry label internally and get its number.  */
> +  rtx entry_label = gen_label_rtx ();
> +  int entry_labelno = CODE_LABEL_NUMBER (entry_label);
> +
> +  /* Generate entry label name with custom prefix.  */
> +  char entry_name[32];
> +  ASM_GENERATE_INTERNAL_LABEL (entry_name, "Lkcfi_entry", entry_labelno);
> +
> +  /* Save current section to restore later.  */
> +  section *saved_section = in_section;
> +
> +  /* Use varasm infrastructure for section handling.  */
> +  section *kcfi_traps_section = get_section (".kcfi_traps",
> +     SECTION_LINK_ORDER, NULL);
> +  switch_to_section (kcfi_traps_section);
> +
> +  /* Emit entry label.  */
> +  ASM_OUTPUT_LABEL (file, entry_name);
> +
> +  /* Generate address difference using RTL infrastructure.  */
> +  rtx entry_label_sym = gen_rtx_SYMBOL_REF (Pmode, entry_name);
> +  rtx addr_diff = gen_rtx_MINUS (Pmode, trap_label_sym, entry_label_sym);
> +
> +  /* Emit the address difference as a 4-byte value.  */
> +  assemble_integer (addr_diff, 4, BITS_PER_UNIT, 1);
> +
> +  /* Restore the previous section.  */
> +  switch_to_section (saved_section);
> +}
> +
> +/* Compute KCFI type ID for a function declaration or function type 
> (internal) */
> +static uint32_t
> +compute_kcfi_type_id (tree fntype, tree fndecl = NULL_TREE)
> +{
> +  gcc_assert (fntype);
> +  gcc_assert (TREE_CODE (fntype) == FUNCTION_TYPE);
> +
> +  uint32_t type_id = hash_function_type (fntype, fndecl);
> +
> +  /* Apply target-specific masking if supported.  */
> +  if (targetm.kcfi.mask_type_id)
> +    type_id = targetm.kcfi.mask_type_id (type_id);
> +
> +  return type_id;
> +}
> +
> +/* Check if a function needs KCFI preamble generation.
> +   ALL functions get preambles when -fsanitize=kcfi is enabled, regardless
> +   of no_sanitize("kcfi") attribute.  */

Why no_sanitize(“kcfi”) is not considered here?

> +static bool
> +function_needs_kcfi_preamble (tree fndecl)
> +{
> +  /* Only instrument if KCFI is globally enabled.  */
> +  if (!(flag_sanitize & SANITIZE_KCFI))
> +    return false;
> +
> +  struct cgraph_node *node = cgraph_node::get (fndecl);
> +
> +  /* Ignore cold partition functions: not reached via indirect call.  */
> +  if (node && node->split_part)
> +    return false;
> +
> +  /* Ignore cold partition sections: cold partitions are never indirect call
> +     targets.  Only skip preambles for cold partitions (has_bb_partition = 
> true)
> +     not for entire cold-attributed functions (has_bb_partition = false).  */
> +  if (in_cold_section_p && crtl && crtl->has_bb_partition)
> +    return false;
> +
> +  /* Check if function is truly address-taken using cgraph node analysis.  */
> +  bool addr_taken = (node && node->address_taken);
> +
> +  /* Only instrument functions that can be targets of indirect calls:
> +     - Public functions (can be called externally)
> +     - External declarations (from other modules)
> +     - Functions with true address-taken status from cgraph analysis.  */
> +  return TREE_PUBLIC (fndecl) || DECL_EXTERNAL (fndecl) || addr_taken;
> +}
> +
> +/* Function attribute to store KCFI type ID.  */
> +static tree kcfi_type_id_attr = NULL_TREE;
> +
> +/* Set KCFI type ID for a function declaration during IPA phase.
> +   Fatal error if type ID is already set.  */
> +static void
> +set_function_kcfi_type_id (tree fndecl)
> +{
> +  if (!kcfi_type_id_attr)
> +    kcfi_type_id_attr = get_identifier ("kcfi_type_id");
> +
> +  /* Fatal error if type ID already set - nothing should set it twice.  */
> +  if (lookup_attribute_by_prefix ("kcfi_type_id",
> +  DECL_ATTRIBUTES (fndecl)))
> +    internal_error ("KCFI type ID already set for function %qD", fndecl);
> +
> +  /* Compute type ID using FUNCTION_TYPE to preserve typedef information.  */
> +  uint32_t type_id = compute_kcfi_type_id (TREE_TYPE (fndecl), fndecl);
> +
> +  tree type_id_tree = build_int_cst (unsigned_type_node, type_id);
> +  tree attr_value = build_tree_list (NULL_TREE, type_id_tree);
> +  tree attr = build_tree_list (kcfi_type_id_attr, attr_value);
> +
> +  DECL_ATTRIBUTES (fndecl) = chainon (DECL_ATTRIBUTES (fndecl), attr);
> +}
> +
> +/* Get KCFI type ID for a function declaration during assembly output phase.
> +   Fatal error if type ID was not previously set during IPA phase.  */
> +static uint32_t
> +get_function_kcfi_type_id (tree fndecl)
> +{
> +  if (!kcfi_type_id_attr)
> +    kcfi_type_id_attr = get_identifier ("kcfi_type_id");
> +
> +  tree attr = lookup_attribute_by_prefix ("kcfi_type_id",
> +   DECL_ATTRIBUTES (fndecl));
> +  if (attr && TREE_VALUE (attr) && TREE_VALUE (TREE_VALUE (attr)))
> +    {
> +      tree value = TREE_VALUE (TREE_VALUE (attr));
> +      if (TREE_CODE (value) == INTEGER_CST)
> + return (uint32_t) TREE_INT_CST_LOW (value);
The indentation of above is off.

> +    }
> +
> +  internal_error ("KCFI type ID not found for function %qD - "
> +  "should have been set during GIMPLE phase", fndecl);
> +}
> +
> +/* Prepare the global KCFI alignment NOPs calculation.
> +   Called once during IPA pass to set global variable.  */
> +static void
> +kcfi_prepare_alignment_nops (void)
> +{
> +  /* Only use global patchable-function-entry flag, not function attributes.
> +     KCFI callsites cannot know about function-specific attributes.  */
> +  if (flag_patchable_function_entry)
> +    {
> +      HOST_WIDE_INT total_nops, prefix_nops = 0;
> +      parse_and_check_patch_area (flag_patchable_function_entry, false,
> +  &total_nops, &prefix_nops);
> +      /* Store value for callsite offset calculation */
> +      kcfi_patchable_entry_prefix_nops = prefix_nops;
> +    }
> +
> +  /* Calculate architecture-specific alignment NOPs.
> +     KCFI preamble layout:
> +     __cfi_func: [alignment_nops][typeid][prefix_nops] func: [entry_nops]
> +
> +     The alignment NOPs ensure __cfi_func stays at proper function alignment
> +     when prefix NOPs are added.  */
> +  HOST_WIDE_INT arch_alignment = 0;
> +
> +  /* Calculate alignment NOPs based on function alignment setting.
> +     Use explicit -falign-functions if set, otherwise default to 4 bytes. */
> +  int alignment_bytes = 4;
> +  if (align_functions.levels[0].log > 0)
> +    {
> +      /* Use explicit -falign-functions setting */
> +      alignment_bytes = align_functions.levels[0].get_value();
> +    }
> +
> +  /* Get typeid instruction size from target hook, default to 4 bytes */
> +  int typeid_size = targetm.kcfi.emit_type_id
> +                    ? targetm.kcfi.emit_type_id (NULL, 0) : 4;
> +
> +  /* Calculate alignment NOPs needed */
> +  arch_alignment = (alignment_bytes - ((kcfi_patchable_entry_prefix_nops + 
> typeid_size) % alignment_bytes)) % alignment_bytes;
The above line is too long. 
> +
> +  /* Use the calculated alignment NOPs */
> +  kcfi_patchable_entry_arch_alignment_nops = arch_alignment;
> +}
> +
> +/* Check if this is an indirect call that needs KCFI instrumentation.  */
> +static bool
> +is_kcfi_indirect_call (tree fn)
> +{
> +  if (!fn)
> +    return false;
> +
> +  /* Only functions WITHOUT no_sanitize("kcfi") should generate KCFI checks 
> at
> +     indirect call sites.  */
> +  if (!sanitize_flags_p (SANITIZE_KCFI, current_function_decl))
> +    return false;
> +
> +  /* Direct function calls via ADDR_EXPR don't need KCFI checks.  */
> +  if (TREE_CODE (fn) == ADDR_EXPR)
> +    return false;
> +
> +  /* Everything else must be indirect calls needing KCFI.  */
> +  return true;
> +}
> +
> +/* Extract KCFI type ID from indirect call GIMPLE statement.
> +   Returns RTX constant with type ID, or NULL_RTX if no KCFI needed.  */
> +rtx
> +kcfi_get_call_type_id (void)
> +{
> +  if (!sanitize_flags_p (SANITIZE_KCFI) || !currently_expanding_gimple_stmt)
> +    return NULL_RTX;
> +
> +  if (!is_gimple_call (currently_expanding_gimple_stmt))
> +    return NULL_RTX;
> +
> +  gcall *call_stmt = as_a <gcall *> (currently_expanding_gimple_stmt);
> +
> +  /* Only indirect calls need KCFI instrumentation.  */
> +  if (gimple_call_fndecl (call_stmt))
> +    return NULL_RTX;
> +
> +  tree fn_type = gimple_call_fntype (call_stmt);
> +  if (!fn_type)
> +    return NULL_RTX;
> +
> +  tree attr = lookup_attribute ("kcfi_type_id", TYPE_ATTRIBUTES (fn_type));
> +  if (!attr || !TREE_VALUE (attr))
> +    return NULL_RTX;
> +
> +  if (gimple_call_inlined_from_kcfi_nosantize_p (call_stmt))
> +    return NULL_RTX;
> +
> +  uint32_t kcfi_type_id = (uint32_t) tree_to_uhwi (TREE_VALUE (attr));
> +  return GEN_INT (kcfi_type_id);
> +}
> +
> +/* Emit KCFI type ID symbol for an address-taken function.
> +   Centralized emission point to avoid duplication between
> +   assemble_external_real() and assemble_start_function(). */
> +void
> +emit_kcfi_typeid_symbol (FILE *asm_file, tree decl, const char *name)
> +{
> +  uint32_t type_id = get_function_kcfi_type_id (decl);
> +  fprintf (asm_file, "\t.weak\t__kcfi_typeid_%s\n", name);
> +  fprintf (asm_file, "\t.set\t__kcfi_typeid_%s, 0x%08x\n", name, type_id);
> +}
> +
> +void
> +kcfi_emit_preamble (FILE *file, tree decl, const char *actual_fname)
> +{
> +  /* Check if KCFI is enabled and function needs preamble.  */
> +  if (!function_needs_kcfi_preamble (decl))
> +    return;
> +
> +  /* Use actual function name if provided, otherwise fall back to 
> DECL_ASSEMBLER_NAME.  */
> +  const char *fname = actual_fname ? actual_fname
> +   : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
> +
> +  /* Get type ID.  */
> +  uint32_t type_id = get_function_kcfi_type_id (decl);
> +
> +  /* Create symbol name for reuse.  */
> +  char cfi_symbol_name[256];
> +  snprintf (cfi_symbol_name, sizeof(cfi_symbol_name), "__cfi_%s", fname);
> +
> +  /* Emit __cfi_ symbol with proper visibility.  */
> +  if (TREE_PUBLIC (decl))
> +    {
> +      if (DECL_WEAK (decl))
> + ASM_WEAKEN_LABEL (file, cfi_symbol_name);
> +      else
> + targetm.asm_out.globalize_label (file, cfi_symbol_name);
> +    }

Indentations are off in the above lines.
> +
> +  /* Emit .type directive.  */
> +  ASM_OUTPUT_TYPE_DIRECTIVE (file, cfi_symbol_name, "function");
> +  fprintf (file, "%s:\n", cfi_symbol_name);
> +
> +  /* Emit architecture-specific prefix NOPs.  */
> +  for (int i = 0; i < kcfi_patchable_entry_arch_alignment_nops; i++)
> +    {
> +      fprintf (file, "\tnop\n");
> +    }
> +
> +  /* Emit type ID bytes.  */
> +  if (targetm.kcfi.emit_type_id)
> +    targetm.kcfi.emit_type_id (file, type_id);
> +  else
> +    fprintf (file, "\t.word\t0x%08x\n", type_id);
> +
> +  /* Mark end of __cfi_ symbol and emit size directive.  */
> +  char cfi_end_label[256];
> +  snprintf (cfi_end_label, sizeof(cfi_end_label), ".Lcfi_func_end_%s", 
> fname);
> +  ASM_OUTPUT_LABEL (file, cfi_end_label);
> +
> +  ASM_OUTPUT_MEASURED_SIZE (file, cfi_symbol_name);
> +}
> +
> +/* KCFI GIMPLE pass implementation.  */
> +
> +static bool
> +gate_kcfi (void)
> +{
> +  /* Always process functions when KCFI is globally enabled to set type IDs.
> +     Individual function processing (call instrumentation) will check 
> no_sanitize("kcfi").  */
> +  return sanitize_flags_p (SANITIZE_KCFI);
> +}
> +
> +/* Create a KCFI wrapper function type that embeds the type ID.  */
> +static tree
> +create_kcfi_wrapper_type (tree original_fn_type, uint32_t type_id)
> +{
> +  /* Create a unique type name incorporating the type ID.  */
> +  char wrapper_name[32];
> +  snprintf (wrapper_name, sizeof (wrapper_name), "__kcfi_wrapper_%x", 
> type_id);
> +
> +  /* Build a new function type that's structurally identical but nominally 
> different.  */
> +  tree wrapper_type = build_function_type (TREE_TYPE (original_fn_type),
> +   TYPE_ARG_TYPES (original_fn_type));
> +
> +  /* Set the type name to make it distinct.  */
> +  TYPE_NAME (wrapper_type) = get_identifier (wrapper_name);
> +
> +  /* Attach kcfi_type_id attribute to the original function type for 
> cfgexpand.cc */
> +  tree attr_name = get_identifier ("kcfi_type_id");
> +  tree attr_value = build_int_cst (unsigned_type_node, type_id);
> +  tree attr = build_tree_list (attr_name, attr_value);
> +  TYPE_ATTRIBUTES (original_fn_type) = chainon (TYPE_ATTRIBUTES 
> (original_fn_type), attr);
> +
> +  return wrapper_type;
> +}
As I asked previously, In the above routine, the “type_id" is attached as an 
attribute to the
 “original_fn_type” already, what additional information is carried by the new 
“wrapper_type”?

> +
> +/* Wrap indirect calls with KCFI type for anti-merging.  */
> +static unsigned int
> +kcfi_instrument (void)
> +{
> +  /* Process current function for call instrumentation only.
> +     Type ID setting is handled by the separate IPA pass.  */
> +
> +  basic_block bb;
> +
> +  FOR_EACH_BB_FN (bb, cfun)
> +    {
> +      gimple_stmt_iterator gsi;
> +      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> + {

The indentation of the above line is off.

> +  gimple *stmt = gsi_stmt (gsi);
> +
> +  if (!is_gimple_call (stmt))
> +    continue;
> +
> +  gcall *call_stmt = as_a <gcall *> (stmt);
> +
> +  // Skip internal calls - we only instrument indirect calls
> +  if (gimple_call_internal_p (call_stmt))
> +    continue;
> +
> +  tree fndecl = gimple_call_fndecl (call_stmt);
> +
> +  // Only process indirect calls (no fndecl)
> +  if (fndecl)
> +    continue;
> +
> +  tree fn = gimple_call_fn (call_stmt);
> +  if (!is_kcfi_indirect_call (fn))
> +    continue;
> +
> +  // Get the function type to compute KCFI type ID
> +  tree fn_type = gimple_call_fntype (call_stmt);
> +  gcc_assert (fn_type);
> +  if (TREE_CODE (fn_type) != FUNCTION_TYPE)
> +    continue;
> +
> +  uint32_t type_id = compute_kcfi_type_id (fn_type);
> +
> +  // Create KCFI wrapper type for this call
> +  tree wrapper_type = create_kcfi_wrapper_type (fn_type, type_id);
Again, the new “type_id” has been attached as an attribute of “fn_type” here, 
> +
> +  // Create a temporary variable for the wrapped function pointer
> +  tree wrapper_ptr_type = build_pointer_type (wrapper_type);
> +  tree wrapper_tmp = create_tmp_var (wrapper_ptr_type, "kcfi_wrapper");
> +
> +  // Create assignment: wrapper_tmp = (wrapper_ptr_type) fn
> +  tree cast_expr = build1 (NOP_EXPR, wrapper_ptr_type, fn);
> +  gimple *cast_stmt = gimple_build_assign (wrapper_tmp, cast_expr);
> +  gsi_insert_before (&gsi, cast_stmt, GSI_SAME_STMT);
> +

Why the additional wrapper_ptr_type, wrapper_tmp and new assignment stmt 
Are needed here?

> +  // Update the call to use the wrapped function pointer
> +  gimple_call_set_fn (call_stmt, wrapper_tmp);
> + }
> +    }
> +
> +  return 0;
> +}
> +
> +namespace {
> +
> +const pass_data pass_data_kcfi =
> +{
> +  GIMPLE_PASS, /* type */
> +  "kcfi", /* name */
> +  OPTGROUP_NONE, /* optinfo_flags */
> +  TV_NONE, /* tv_id */
> +  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
> +  0, /* properties_provided */
> +  0, /* properties_destroyed */
> +  0, /* todo_flags_start */
> +  TODO_update_ssa, /* todo_flags_finish */
> +};
> +
> +class pass_kcfi : public gimple_opt_pass
> +{
> +public:
> +  pass_kcfi (gcc::context *ctxt)
> +    : gimple_opt_pass (pass_data_kcfi, ctxt)
> +  {}
> +
> +  /* opt_pass methods: */
> +  opt_pass * clone () final override { return new pass_kcfi (m_ctxt); }
> +  bool gate (function *) final override
> +  {
> +    return gate_kcfi ();
> +  }
> +  unsigned int execute (function *) final override
> +  {
> +    return kcfi_instrument ();
> +  }
> +
> +}; // class pass_kcfi
> +
> +} // anon namespace
> +
> +gimple_opt_pass *
> +make_pass_kcfi (gcc::context *ctxt)
> +{
> +  return new pass_kcfi (ctxt);
> +}
> +
> +namespace {
> +
> +const pass_data pass_data_kcfi_O0 =
> +{
> +  GIMPLE_PASS, /* type */
> +  "kcfi0", /* name */
> +  OPTGROUP_NONE, /* optinfo_flags */
> +  TV_NONE, /* tv_id */
> +  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
> +  0, /* properties_provided */
> +  0, /* properties_destroyed */
> +  0, /* todo_flags_start */
> +  TODO_update_ssa, /* todo_flags_finish */
> +};
> +
> +class pass_kcfi_O0 : public gimple_opt_pass
> +{
> +public:
> +  pass_kcfi_O0 (gcc::context *ctxt)
> +    : gimple_opt_pass (pass_data_kcfi_O0, ctxt)
> +  {}
> +
> +  /* opt_pass methods: */
> +  bool gate (function *) final override
> +    {
> +      return !optimize && gate_kcfi ();
> +    }
> +  unsigned int execute (function *) final override
> +  {
> +    return kcfi_instrument ();
> +  }
> +
> +}; // class pass_kcfi_O0
> +
> +} // anon namespace
> +
> +gimple_opt_pass *
> +make_pass_kcfi_O0 (gcc::context *ctxt)
> +{
> +  return new pass_kcfi_O0 (ctxt);
> +}
> +
> +/* IPA pass for KCFI type ID setting - runs once per compilation unit.  */
> +
> +namespace {
> +
> +const pass_data pass_data_ipa_kcfi =
> +{
> +  SIMPLE_IPA_PASS, /* type */
> +  "ipa_kcfi", /* name */
> +  OPTGROUP_NONE, /* optinfo_flags */
> +  TV_IPA_OPT, /* tv_id */
> +  0, /* properties_required */
> +  0, /* properties_provided */
> +  0, /* properties_destroyed */
> +  0, /* todo_flags_start */
> +  0, /* todo_flags_finish */
> +};
> +
> +/* Set KCFI type IDs for all functions in the compilation unit.  */
> +static unsigned int
> +ipa_kcfi_execute (void)
> +{
> +  struct cgraph_node *node;
> +
> +  /* Prepare global KCFI alignment NOPs calculation once for all functions.  
> */
> +  kcfi_prepare_alignment_nops ();
> +
> +  /* Process all functions - both local and external.
> +     This preserves typedef information using DECL_ARGUMENTS.  */
> +  FOR_EACH_FUNCTION (node)
> +    {
> +      tree fndecl = node->decl;
> +
> +      /* Skip all non-NORMAL builtins (MD, FRONTEND) entirely.
> +         For NORMAL builtins, skip those that lack an implicit
> + implementation (closest way to distinguishing DEF_LIB_BUILTIN
> + from others). E.g. we need to have typeids for memset().  */
> +      if (fndecl_built_in_p (fndecl))
> +        {
> +          if (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
> +            continue;
> +          if (!builtin_decl_implicit_p (DECL_FUNCTION_CODE (fndecl)))
> +            continue;
> +        }
> +
> +      set_function_kcfi_type_id (fndecl);
> +    }
> +
> +  return 0;
> +}
> +
> +class pass_ipa_kcfi : public simple_ipa_opt_pass
> +{
> +public:
> +  pass_ipa_kcfi (gcc::context *ctxt)
> +    : simple_ipa_opt_pass (pass_data_ipa_kcfi, ctxt)
> +  {}
> +
> +  /* opt_pass methods: */
> +  bool gate (function *) final override
> +  {
> +    return sanitize_flags_p (SANITIZE_KCFI);
> +  }
> +
> +  unsigned int execute (function *) final override
> +  {
> +    return ipa_kcfi_execute ();
> +  }
> +
> +}; // class pass_ipa_kcfi
> +
> +} // anon namespace
> +
> +simple_ipa_opt_pass *
> +make_pass_ipa_kcfi (gcc::context *ctxt)
> +{
> +  return new pass_ipa_kcfi (ctxt);
> +}
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 4c12ac68d979..84bbc4223734 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1591,6 +1591,7 @@ OBJS = \
> ira-emit.o \
> ira-lives.o \
> jump.o \
> + kcfi.o \
> langhooks.o \
> late-combine.o \
> lcm.o \
> diff --git a/gcc/flag-types.h b/gcc/flag-types.h
> index bf681c3e8153..c3c0bc61ee3e 100644
> --- a/gcc/flag-types.h
> +++ b/gcc/flag-types.h
> @@ -337,6 +337,8 @@ enum sanitize_code {
>   SANITIZE_KERNEL_HWADDRESS = 1UL << 30,
>   /* Shadow Call Stack.  */
>   SANITIZE_SHADOW_CALL_STACK = 1UL << 31,
> +  /* KCFI (Kernel Control Flow Integrity) */
> +  SANITIZE_KCFI = 1ULL << 32,
>   SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
>   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
>       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index da32651ea017..cef915b9164f 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -142,6 +142,7 @@ enum gf_mask {
>     GF_CALL_ALLOCA_FOR_VAR = 1 << 5,
>     GF_CALL_INTERNAL = 1 << 6,
>     GF_CALL_CTRL_ALTERING       = 1 << 7,
> +    GF_CALL_INLINED_FROM_KCFI_NOSANTIZE = 1 << 8,
>     GF_CALL_MUST_TAIL_CALL = 1 << 9,
>     GF_CALL_BY_DESCRIPTOR = 1 << 10,
>     GF_CALL_NOCF_CHECK = 1 << 11,
> @@ -3487,6 +3488,26 @@ gimple_call_from_thunk_p (gcall *s)
>   return (s->subcode & GF_CALL_FROM_THUNK) != 0;
> }
> 
> +/* If INLINED_FROM_KCFI_NOSANTIZE_P is true, mark GIMPLE_CALL S as being
> +   inlined from a function with no_sanitize("kcfi").  */
> +
> +inline void
> +gimple_call_set_inlined_from_kcfi_nosantize (gcall *s, bool 
> inlined_from_kcfi_nosantize_p)
> +{
> +  if (inlined_from_kcfi_nosantize_p)
> +    s->subcode |= GF_CALL_INLINED_FROM_KCFI_NOSANTIZE;
> +  else
> +    s->subcode &= ~GF_CALL_INLINED_FROM_KCFI_NOSANTIZE;
> +}
> +
> +/* Return true if GIMPLE_CALL S was inlined from a function with
> +   no_sanitize("kcfi").  */
> +
> +inline bool
> +gimple_call_inlined_from_kcfi_nosantize_p (const gcall *s)
> +{
> +  return (s->subcode & GF_CALL_INLINED_FROM_KCFI_NOSANTIZE) != 0;
> +}
> 
> /* If FROM_NEW_OR_DELETE_P is true, mark GIMPLE_CALL S as being a call
>    to operator new or delete created from a new or delete expression.  */
> diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
> index 1c68a69350df..fbf235adada3 100644
> --- a/gcc/tree-pass.h
> +++ b/gcc/tree-pass.h
> @@ -357,6 +357,8 @@ extern gimple_opt_pass *make_pass_tsan (gcc::context 
> *ctxt);
> extern gimple_opt_pass *make_pass_tsan_O0 (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_sancov (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_sancov_O0 (gcc::context *ctxt);
> +extern gimple_opt_pass *make_pass_kcfi (gcc::context *ctxt);
> +extern gimple_opt_pass *make_pass_kcfi_O0 (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_lower_cf (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_refactor_eh (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_lower_eh (gcc::context *ctxt);
> @@ -544,6 +546,7 @@ extern ipa_opt_pass_d *make_pass_ipa_odr (gcc::context 
> *ctxt);
> extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt);
> extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt);
> extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt);
> +extern simple_ipa_opt_pass *make_pass_ipa_kcfi (gcc::context *ctxt);
> extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt);
> extern simple_ipa_opt_pass *make_pass_target_clone (gcc::context *ctxt);
> extern simple_ipa_opt_pass *make_pass_dispatcher_calls (gcc::context *ctxt);
> diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> index 1e3a94ed9493..a12cfe48772a 100644
> --- a/gcc/c-family/c-attribs.cc
> +++ b/gcc/c-family/c-attribs.cc
> @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
> #include "gimplify.h"
> #include "tree-pretty-print.h"
> #include "gcc-rich-location.h"
> +#include "asan.h"
> #include "gcc-urlifier.h"
> 
> static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
> @@ -6508,6 +6509,17 @@ static tree
> handle_patchable_function_entry_attribute (tree *, tree name, tree args,
>   int, bool *no_add_attrs)
> {
> +  /* Function-specific patchable_function_entry attribute is incompatible
> +     with KCFI because KCFI callsites cannot know about function-specific
> +     patchable entry settings on a preamble in a different translation
> +     unit.  */
> +  if (sanitize_flags_p (SANITIZE_KCFI))
> +    {
> +      error ("%qE attribute cannot be used with %<-fsanitize=kcfi%>", name);
> +      *no_add_attrs = true;
> +      return NULL_TREE;
> +    }
> +
>   for (; args; args = TREE_CHAIN (args))
>     {
>       tree val = TREE_VALUE (args);
> diff --git a/gcc/df-scan.cc b/gcc/df-scan.cc
> index 1e4c6a2a4fb5..0e9c75df48dd 100644
> --- a/gcc/df-scan.cc
> +++ b/gcc/df-scan.cc
> @@ -2851,6 +2851,12 @@ df_uses_record (class df_collection_rec 
> *collection_rec,
>       /* If we're clobbering a REG then we have a def so ignore.  */
>       return;
> 
> +    case KCFI:
> +      /* KCFI wraps other RTL - process the wrapped RTL.  */
> +      df_uses_record (collection_rec, &XEXP (x, 0), ref_type, bb, insn_info, 
> flags);
> +      /* The type ID operand (XEXP (x, 1)) doesn't contain register uses.  */
> +      return;
> +
>     case MEM:
>       df_uses_record (collection_rec,
>      &XEXP (x, 0), DF_REF_REG_MEM_LOAD,
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 56c4fa86e346..cd70e6351a4e 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -18382,6 +18382,41 @@ possible by specifying the command-line options
> @option{--param hwasan-instrument-allocas=1} respectively. Using a random 
> frame
> tag is not implemented for kernel instrumentation.
> 
> +@opindex fsanitize=kcfi
> +@item -fsanitize=kcfi
> +Enable Kernel Control Flow Integrity (KCFI), a lightweight control
> +flow integrity mechanism designed for operating system kernels.
> +KCFI instruments indirect function calls to verify that the target
> +function has the expected type signature at runtime.  Each function
> +receives a unique type identifier computed from a hash of its function
> +prototype (including parameter types and return type).  Before each
> +indirect call, the implementation inserts a check to verify that the
> +target function's type identifier matches the expected identifier
> +for the call site, terminating the program if a mismatch is detected.
> +This provides forward-edge control flow protection against attacks that
> +attempt to redirect indirect calls to unintended targets.
> +
> +The implementation adds minimal runtime overhead and does not require
> +runtime library support, making it suitable for kernel environments.
> +The type identifier is placed before the function entry point,
> +allowing runtime verification without additional metadata structures,
> +and without changing the entry points of the target functions. Only
> +functions that have referenced by their address receive the KCFI preamble
> +instrumentation.
> +
> +KCFI is intended primarily for kernel code and may not be suitable
> +for user-space applications that rely on techniques incompatible
> +with strict type checking of indirect calls.
> +
> +Note that KCFI is incompatible with function-specific
> +@code{patchable_function_entry} attributes because KCFI call sites
> +cannot know about function-specific patchable entry settings in different
> +translation units.  Only the global @option{-fpatchable-function-entry}
> +command-line option is supported with KCFI.
> +
> +Use @option{-fdump-tree-kcfi} to examine the computed type identifiers
> +and their corresponding mangled type strings during compilation.
> +
> @opindex fsanitize=pointer-compare
> @item -fsanitize=pointer-compare
> Instrument comparison operation (<, <=, >, >=) with pointer operands.
> diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
> index 37642680f423..69603fdad090 100644
> --- a/gcc/doc/tm.texi
> +++ b/gcc/doc/tm.texi
> @@ -3166,6 +3166,7 @@ This describes the stack layout and calling conventions.
> * Tail Calls::
> * Shrink-wrapping separate components::
> * Stack Smashing Protection::
> +* Kernel Control Flow Integrity::
> * Miscellaneous Register Hooks::
> @end menu
> 
> @@ -5432,6 +5433,36 @@ should be allocated from heap memory and consumers 
> should release them.
> The result will be pruned to cases with PREFIX if not NULL.
> @end deftypefn
> 
> +@node Kernel Control Flow Integrity
> +@subsection Kernel Control Flow Integrity
> +@cindex kernel control flow integrity
> +@cindex KCFI
> +
> +@deftypefn {Target Hook} bool TARGET_KCFI_SUPPORTED (void)
> +Return true if the target supports Kernel Control Flow Integrity (KCFI).
> +This hook indicates whether the target has implemented the necessary RTL
> +patterns and infrastructure to support KCFI instrumentation.  The default
> +implementation returns false.
> +@end deftypefn
> +
> +@deftypefn {Target Hook} uint32_t TARGET_KCFI_MASK_TYPE_ID (uint32_t 
> @var{type_id})
> +Apply architecture-specific masking to KCFI type ID.  This hook allows
> +targets to apply bit masks or other transformations to the computed KCFI
> +type identifier to match the target's specific requirements.  The default
> +implementation returns the type ID unchanged.
> +@end deftypefn
> +
> +@deftypefn {Target Hook} int TARGET_KCFI_EMIT_TYPE_ID (FILE *@var{file}, 
> uint32_t @var{type_id})
> +Emit architecture-specific type ID instruction for KCFI preambles
> +and return the size of the instruction in bytes.
> +@var{file} is the assembly output stream and @var{type_id} is the KCFI
> +type identifier to emit.  If @var{file} is NULL, skip emission and only
> +return the size.  If not overridden, the default fallback emits a
> +@code{.word} directive with the type ID and returns 4 bytes.  Targets can
> +override this to emit different instruction sequences and return their
> +corresponding sizes.
> +@end deftypefn
> +
> @node Miscellaneous Register Hooks
> @subsection Miscellaneous register hooks
> @cindex miscellaneous register hooks
> diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
> index c3ed9a9fd7c2..b2856886194c 100644
> --- a/gcc/doc/tm.texi.in
> +++ b/gcc/doc/tm.texi.in
> @@ -2433,6 +2433,7 @@ This describes the stack layout and calling conventions.
> * Tail Calls::
> * Shrink-wrapping separate components::
> * Stack Smashing Protection::
> +* Kernel Control Flow Integrity::
> * Miscellaneous Register Hooks::
> @end menu
> 
> @@ -3807,6 +3808,17 @@ generic code.
> 
> @hook TARGET_GET_VALID_OPTION_VALUES
> 
> +@node Kernel Control Flow Integrity
> +@subsection Kernel Control Flow Integrity
> +@cindex kernel control flow integrity
> +@cindex KCFI
> +
> +@hook TARGET_KCFI_SUPPORTED
> +
> +@hook TARGET_KCFI_MASK_TYPE_ID
> +
> +@hook TARGET_KCFI_EMIT_TYPE_ID
> +
> @node Miscellaneous Register Hooks
> @subsection Miscellaneous register hooks
> @cindex miscellaneous register hooks
> diff --git a/gcc/final.cc b/gcc/final.cc
> index afcb0bb9efbc..7f6aa9f9e480 100644
> --- a/gcc/final.cc
> +++ b/gcc/final.cc
> @@ -2094,6 +2094,9 @@ call_from_call_insn (const rtx_call_insn *insn)
> case SET:
>  x = XEXP (x, 1);
>  break;
> + case KCFI:
> +  x = XEXP (x, 0);
> +  break;
> }
>     }
>   return x;
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 3ab993aea573..0ee37e01d24a 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -2170,6 +2170,7 @@ const struct sanitizer_opts_s sanitizer_opts[] =
>   SANITIZER_OPT (pointer-overflow, SANITIZE_POINTER_OVERFLOW, true, true),
>   SANITIZER_OPT (builtin, SANITIZE_BUILTIN, true, true),
>   SANITIZER_OPT (shadow-call-stack, SANITIZE_SHADOW_CALL_STACK, false, false),
> +  SANITIZER_OPT (kcfi, SANITIZE_KCFI, false, true),
>   SANITIZER_OPT (all, ~sanitize_code_type (0), true, true),
> #undef SANITIZER_OPT
>   { NULL, sanitize_code_type (0), 0UL, false, false }
> diff --git a/gcc/passes.cc b/gcc/passes.cc
> index a33c8d924a52..4c6ceac740ff 100644
> --- a/gcc/passes.cc
> +++ b/gcc/passes.cc
> @@ -63,6 +63,7 @@ along with GCC; see the file COPYING3.  If not see
> #include "diagnostic-core.h" /* for fnotice */
> #include "stringpool.h"
> #include "attribs.h"
> +#include "kcfi.h"
> 
> /* Reserved TODOs */
> #define TODO_verify_il (1u << 31)
> diff --git a/gcc/passes.def b/gcc/passes.def
> index 68ce53baa0f1..fd1bb0846801 100644
> --- a/gcc/passes.def
> +++ b/gcc/passes.def
> @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3.  If not see
>   NEXT_PASS (pass_ipa_auto_profile_offline);
>   NEXT_PASS (pass_ipa_free_lang_data);
>   NEXT_PASS (pass_ipa_function_and_variable_visibility);
> +  NEXT_PASS (pass_ipa_kcfi);
>   NEXT_PASS (pass_ipa_strub_mode);
>   NEXT_PASS (pass_build_ssa_passes);
>   PUSH_INSERT_PASSES_WITHIN (pass_build_ssa_passes)
> @@ -275,6 +276,7 @@ along with GCC; see the file COPYING3.  If not see
>       NEXT_PASS (pass_sink_code, false /* unsplit edges */);
>       NEXT_PASS (pass_sancov);
>       NEXT_PASS (pass_asan);
> +      NEXT_PASS (pass_kcfi);
>       NEXT_PASS (pass_tsan);
>       NEXT_PASS (pass_dse, true /* use DR analysis */);
>       NEXT_PASS (pass_dce, false /* update_address_taken_p */, false /* 
> remove_unused_locals */);
> @@ -443,6 +445,7 @@ along with GCC; see the file COPYING3.  If not see
>   NEXT_PASS (pass_sancov_O0);
>   NEXT_PASS (pass_lower_switch_O0);
>   NEXT_PASS (pass_asan_O0);
> +  NEXT_PASS (pass_kcfi_O0);
>   NEXT_PASS (pass_tsan_O0);
>   NEXT_PASS (pass_musttail);
>   NEXT_PASS (pass_sanopt);
> diff --git a/gcc/rtl.def b/gcc/rtl.def
> index 15ae7d10fcc1..af643d187b95 100644
> --- a/gcc/rtl.def
> +++ b/gcc/rtl.def
> @@ -318,6 +318,12 @@ DEF_RTL_EXPR(CLOBBER, "clobber", "e", RTX_EXTRA)
> 
> DEF_RTL_EXPR(CALL, "call", "ee", RTX_EXTRA)
> 
> +/* KCFI wrapper for call expressions.
> +   Operand 0 is the call expression.
> +   Operand 1 is the KCFI type ID (const_int).  */
> +
> +DEF_RTL_EXPR(KCFI, "kcfi", "ee", RTX_EXTRA)
> +
> /* Return from a subroutine.  */
> 
> DEF_RTL_EXPR(RETURN, "return", "", RTX_EXTRA)
> diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc
> index 63a1d08c46cf..4baa820b176e 100644
> --- a/gcc/rtlanal.cc
> +++ b/gcc/rtlanal.cc
> @@ -1177,6 +1177,11 @@ reg_referenced_p (const_rtx x, const_rtx body)
>     case IF_THEN_ELSE:
>       return reg_overlap_mentioned_p (x, body);
> 
> +    case KCFI:
> +      /* For KCFI wrapper, check both the wrapped call and the type ID */
> +      return (reg_overlap_mentioned_p (x, XEXP (body, 0))
> +              || reg_overlap_mentioned_p (x, XEXP (body, 1)));
> +
>     case TRAP_IF:
>       return reg_overlap_mentioned_p (x, TRAP_CONDITION (body));
> 
> diff --git a/gcc/target.def b/gcc/target.def
> index 8e491d838642..47a11c60809a 100644
> --- a/gcc/target.def
> +++ b/gcc/target.def
> @@ -7589,6 +7589,44 @@ DEFHOOKPOD
> The default value is NULL.",
>  const char *, NULL)
> 
> +/* Kernel Control Flow Integrity (KCFI) hooks.  */
> +#undef HOOK_PREFIX
> +#define HOOK_PREFIX "TARGET_KCFI_"
> +HOOK_VECTOR (TARGET_KCFI, kcfi)
> +
> +DEFHOOK
> +(supported,
> + "Return true if the target supports Kernel Control Flow Integrity (KCFI).\n\
> +This hook indicates whether the target has implemented the necessary RTL\n\
> +patterns and infrastructure to support KCFI instrumentation.  The default\n\
> +implementation returns false.",
> + bool, (void),
> + hook_bool_void_false)
> +
> +DEFHOOK
> +(mask_type_id,
> + "Apply architecture-specific masking to KCFI type ID.  This hook allows\n\
> +targets to apply bit masks or other transformations to the computed KCFI\n\
> +type identifier to match the target's specific requirements.  The default\n\
> +implementation returns the type ID unchanged.",
> + uint32_t, (uint32_t type_id),
> + NULL)
> +
> +DEFHOOK
> +(emit_type_id,
> + "Emit architecture-specific type ID instruction for KCFI preambles\n\
> +and return the size of the instruction in bytes.\n\
> +@var{file} is the assembly output stream and @var{type_id} is the KCFI\n\
> +type identifier to emit.  If @var{file} is NULL, skip emission and only\n\
> +return the size.  If not overridden, the default fallback emits a\n\
> +@code{.word} directive with the type ID and returns 4 bytes.  Targets can\n\
> +override this to emit different instruction sequences and return their\n\
> +corresponding sizes.",
> + int, (FILE *file, uint32_t type_id),
> + NULL)
> +
> +HOOK_VECTOR_END (kcfi)
> +
> /* Close the 'struct gcc_target' definition.  */
> HOOK_VECTOR_END (C90_EMPTY_HACK)
> 
> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
> index d26467450e37..9078bb6318a9 100644
> --- a/gcc/toplev.cc
> +++ b/gcc/toplev.cc
> @@ -67,6 +67,7 @@ along with GCC; see the file COPYING3.  If not see
> #include "attribs.h"
> #include "asan.h"
> #include "tsan.h"
> +#include "kcfi.h"
> #include "plugin.h"
> #include "context.h"
> #include "pass_manager.h"
> @@ -1739,6 +1740,16 @@ process_options ()
>  "requires %<-fno-exceptions%>");
>     }
> 
> +  if (flag_sanitize & SANITIZE_KCFI)
> +    {
> +      if (!targetm.kcfi.supported ())
> + sorry ("%<-fsanitize=kcfi%> not supported by this target");
> +
> +      /* KCFI is supported for only C at this time.  */
> +      if (!lang_GNU_C ())
> + sorry ("%<-fsanitize=kcfi%> is only supported for C");
> +    }
> +
>   HOST_WIDE_INT patch_area_size, patch_area_start;
>   parse_and_check_patch_area (flag_patchable_function_entry, false,
>      &patch_area_size, &patch_area_start);
> diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
> index 08e642178ba5..e674e176f7d3 100644
> --- a/gcc/tree-inline.cc
> +++ b/gcc/tree-inline.cc
> @@ -2104,6 +2104,16 @@ copy_bb (copy_body_data *id, basic_block bb,
>  /* Advance iterator now before stmt is moved to seq_gsi.  */
>  gsi_next (&stmts_gsi);
> 
> +  /* If inlining from a function with no_sanitize("kcfi"), mark any
> +     call statements in the inlined body with the flag so they skip
> +     KCFI instrumentation.  */
> +  if (is_gimple_call (stmt)
> +      && !sanitize_flags_p (SANITIZE_KCFI, id->src_fn))
> +    {
> +      gcall *call = as_a <gcall *> (stmt);
> +      gimple_call_set_inlined_from_kcfi_nosantize (call, true);
> +    }
> +
>  if (gimple_nop_p (stmt))
>      continue;
> 
> diff --git a/gcc/varasm.cc b/gcc/varasm.cc
> index 0d78f5b384fb..b897954fd0ea 100644
> --- a/gcc/varasm.cc
> +++ b/gcc/varasm.cc
> @@ -57,6 +57,7 @@ along with GCC; see the file COPYING3.  If not see
> #include "attribs.h"
> #include "asan.h"
> #include "rtl-iter.h"
> +#include "kcfi.h"
> #include "file-prefix-map.h" /* remap_debug_filename()  */
> #include "alloc-pool.h"
> #include "toplev.h"
> @@ -2199,6 +2200,9 @@ assemble_start_function (tree decl, const char *fnname)
>   unsigned short patch_area_size = crtl->patch_area_size;
>   unsigned short patch_area_entry = crtl->patch_area_entry;
> 
> +  /* Emit KCFI preamble before any patchable areas.  */
> +  kcfi_emit_preamble (asm_out_file, decl, fnname);
> +
>   /* Emit the patching area before the entry label, if any.  */
>   if (patch_area_entry > 0)
>     targetm.asm_out.print_patchable_function_entry (asm_out_file,
> @@ -2767,6 +2771,19 @@ assemble_external_real (tree decl)
>       /* Some systems do require some output.  */
>       SYMBOL_REF_USED (XEXP (rtl, 0)) = 1;
>       ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));
> +
> +      /* Emit KCFI type ID symbol for external function declarations that 
> are address-taken.  */
> +      struct cgraph_node *node = (TREE_CODE (decl) == FUNCTION_DECL) ? 
> cgraph_node::get (decl) : NULL;
> +      if (flag_sanitize & SANITIZE_KCFI
> +  && TREE_CODE (decl) == FUNCTION_DECL
> +  && !DECL_INITIAL (decl)  /* Only for external declarations (no function 
> body) */
> +  && node && node->address_taken)  /* Use direct cgraph analysis for 
> address-taken check.  */
> + {
> +  const char *name = XSTR (XEXP (rtl, 0), 0);
> +  /* Strip any encoding prefixes like '*' from symbol name.  */
> +  name = targetm.strip_name_encoding (name);
> +  emit_kcfi_typeid_symbol (asm_out_file, decl, name);
> + }

The indentations of the above lines are off.

Thanks.

Qing
>     }
> }
> #endif
> @@ -7283,16 +7300,25 @@ default_elf_asm_named_section (const char *name, 
> unsigned int flags,
> fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
>       if (flags & SECTION_LINK_ORDER)
> {
> -  /* For now, only section "__patchable_function_entries"
> -     adopts flag SECTION_LINK_ORDER, internal label LPFE*
> -     was emitted in default_print_patchable_function_entry,
> -     just place it here for linked_to section.  */
> -  gcc_assert (!strcmp (name, "__patchable_function_entries"));
> -  fprintf (asm_out_file, ",");
> -  char buf[256];
> -  ASM_GENERATE_INTERNAL_LABEL (buf, "LPFE",
> -       current_function_funcdef_no);
> -  assemble_name_raw (asm_out_file, buf);
> +  if (!strcmp (name, "__patchable_function_entries"))
> +    {
> +      /* For patchable function entries, internal label LPFE*
> + was emitted in default_print_patchable_function_entry,
> + just place it here for linked_to section.  */
> +      fprintf (asm_out_file, ",");
> +      char buf[256];
> +      ASM_GENERATE_INTERNAL_LABEL (buf, "LPFE",
> +   current_function_funcdef_no);
> +      assemble_name_raw (asm_out_file, buf);
> +    }
> +  else if (!strcmp (name, ".kcfi_traps"))
> +    {
> +      /* KCFI traps section links to .text section.  */
> +      fprintf (asm_out_file, ",.text");
> +    }
> +  else
> +    internal_error ("unexpected use of %<SECTION_LINK_ORDER%> by section 
> %qs",
> +    name);
> }
>       if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
> {
> -- 
> 2.34.1
> 

Reply via email to