Re: [PATCH v13 2/7] kcfi: Add core Kernel Control Flow Integrity infrastructure

Kees Cook <[email protected]>
Newsgroups org.kernel.vger.linux-hardening
Message-ID <202607151337.31D0828D0@keescook>
On Sat, Jun 27, 2026 at 03:57:36PM -0700, Andrea Pinski wrote:
> On Thu, Jun 18, 2026 at 1:45 PM Kees Cook <[email protected]> wrote:
> > [...]
> > diff --git a/gcc/kcfi.h b/gcc/kcfi.h
> > new file mode 100644
> > index 000000000000..ea7e7881040f
> > --- /dev/null
> > +++ b/gcc/kcfi.h
> > [...]
> > +#include "config.h"
> > +#include "system.h"
> > +#include "coretypes.h"
> > +#include "rtl.h"
> 
> This is wrong. Don't include config.h nor system.h in a header file.

Okay, removing.

> 
> > +
> > +/* 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,
> > +                                     int labelno);
> > +
> > +/* Extract KCFI type ID from current GIMPLE statement.  */
> > +extern rtx internal_kcfi_get_type_id_for_expanding_gimple_call (void);
> > +
> > +/* Convenience wrapper to check for SANITIZE_KCFI.  */
> > +static inline rtx
> Remove static.

Okay. This is a Linux-ism in my finger, I think. :)

> > [...]
> > --- /dev/null
> > +++ b/gcc/kcfi.cc
> > @@ -0,0 +1,696 @@
> > +/* Kernel Control Flow Integrity (KCFI) support for GCC.
> > +   Copyright (C) 2025 Free Software Foundation, Inc.
> 
> 2026.

Yup, I went and hunted down all of these.

> > [...]
> > +#include "config.h"
> `#define INCLUDE_STRING` is needed based on review of the previous patch.

Got it.

> > [...]
> > +/* KCFI label counter, incremented by KCFI insn emission.  */
> > +static int kcfi_labelno = 0;
> 
> I am not 100% sure if this needs a GTY marker or not. I suspect no
> because we should not have emitted assembly code yet.

If this moves with kcfi_next_labelno into final, I think it's okay
without GTY?

> > +
> > +/* Get next KCFI label number.  Returns the current KCFI label number
> > +   and increments the internal counter for the next call.  The label is
> > +   used to provide a unique number for each indirect callsite of the
> > +   current module of the compilation.  */
> > +
> > +int
> > +kcfi_next_labelno (void)
> > +{
> > +  return kcfi_labelno++;
> > +}
> 
> Seems like this should be instead in `final.{cc,h}` rather than `kfci.{cc,h}`.

I think you want this because it's exclusively used during output phase?
I'll get it moved.

> > +/* Function attribute to store KCFI type ID.  */
> > +static tree kcfi_type_id_attr = NULL_TREE;
> 
> This 100% needs a GTY marker. to make sure the identifier does not get freed.

Got it.

> > +
> > +/* Get KCFI type ID for a function type.  Set it if missing.  FN_TYPE
> > +   is the function type tree node.  Returns the cached or newly computed
> > +   32-bit KCFI type identifier, storing it as a type attribute.  */
> > +
> > +static uint32_t
> > +kcfi_get_type_id (tree fn_type)
> > +{
> > +  uint32_t type_id;
> > +
> > +  /* Cache the attribute identifier for build_tree_list usage.  */
> > +  if (!kcfi_type_id_attr)
> > +    kcfi_type_id_attr = get_identifier ("kcfi_type_id");
> > +
> > +  tree attr = lookup_attribute ("kcfi_type_id", TYPE_ATTRIBUTES (fn_type));
> > +  if (attr)
> > +    {
> > +      tree value = TREE_VALUE (attr);
> > +      gcc_assert (value && TREE_CODE (value) == INTEGER_CST);
> gcc_assert (tree_fits_uhwi_p (value));
> type_id = tree_to_uhwi (value);

Updated.

> > +      type_id = (uint32_t) TREE_INT_CST_LOW (value);
> > +    }
> > +  else
> > +    {
> > +      type_id = compute_kcfi_type_id (fn_type);
> > +
> > +      tree type_id_tree = build_int_cst (unsigned_type_node, type_id);
> > +      tree attr = build_tree_list (kcfi_type_id_attr, type_id_tree);
> > +
> > +      TYPE_ATTRIBUTES (fn_type) = chainon (TYPE_ATTRIBUTES (fn_type), attr);
> > +    }
> 
> Instead of an attribute there must be a better way of doing this.
> Maybe a hashset instead.

Perhaps? I will go examine this vs LTO, etc.

> > [...]
> > +rtx
> > +internal_kcfi_get_type_id_for_expanding_gimple_call (void)
> > +{
> > +  gcc_assert (currently_expanding_gimple_stmt);
> 
> gcall *call_stmt = dyn_cast<gcall *> (currently_expanding_gimple_stmt);
> gcc_assert (call_stmt);

Updated.

> > [...]
> > +  /* Emit .type directive.  */
> > +  ASM_OUTPUT_TYPE_DIRECTIVE (asm_file, cfi_symbol_name.c_str (), "function");
> > +  ASM_OUTPUT_LABEL (asm_file, cfi_symbol_name.c_str ());
> > +
> > +  /* Emit any needed alignment padding NOPs using target's NOP template.  */
> > +  for (int i = 0; i < kcfi_alignment_padding_nops; i++)
> > +    output_asm_insn (kcfi_nop, NULL);
> I think you need to calculate kcfi_nop each time you call this
> function. Instead of caching it. For GC reasons.

Uh, do I have to? This seems wasteful: the nop is generated frequently.
Should kcfi_nop gain GTY instead? I will take a closer look at this.

> > [...]
> > +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.  */
> > +  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;
> > +       }
> > +
> > +      /* Cache the type_id in the function type.  */
> > +      kcfi_get_type_id (TREE_TYPE (fndecl));
> 
> Why are you needing to cache here?

This was originally added for the __kcfi_typeid emission for functions
known to the TU since at the time I couldn't figure out how to deal with
lacking FN_TYPE (to see the function argument types), but that logic
changed in v3, and I never noticed I didn't have to cache it any more.
It looks like I can drop this.

So... we could just not cache this at all, I guess? It seems wrong to
keep resolving the same typeid over and over though. I will look at
hashset, though, as you suggested.

-Kees

-- 
Kees Cook
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.