From: Kees Cook <kees@kernel.org>
To: Qing Zhao <qing.zhao@oracle.com>
Cc: Andrew Pinski <pinskia@gmail.com>,
Richard Biener <rguenther@suse.de>,
Joseph Myers <josmyers@redhat.com>, Jan Hubicka <hubicka@ucw.cz>,
Richard Earnshaw <richard.earnshaw@arm.com>,
Richard Sandiford <richard.sandiford@arm.com>,
Marcus Shawcroft <marcus.shawcroft@arm.com>,
Kyrylo Tkachov <kyrylo.tkachov@arm.com>,
Kito Cheng <kito.cheng@gmail.com>,
Palmer Dabbelt <palmer@dabbelt.com>,
Andrew Waterman <andrew@sifive.com>,
Jim Wilson <jim.wilson.gcc@gmail.com>,
Peter Zijlstra <peterz@infradead.org>,
Dan Li <ashimida.1990@gmail.com>,
Sami Tolvanen <samitolvanen@google.com>,
Ramon de C Valle <rcvalle@google.com>,
Joao Moreira <joao@overdrivepizza.com>,
Nathan Chancellor <nathan@kernel.org>,
Bill Wendling <morbo@google.com>,
"gcc-patches@gcc.gnu.org" <gcc-patches@gcc.gnu.org>,
"linux-hardening@vger.kernel.org"
<linux-hardening@vger.kernel.org>
Subject: Re: [PATCH v2 2/7] kcfi: Add core Kernel Control Flow Integrity infrastructure
Date: Wed, 10 Sep 2025 20:05:11 -0700 [thread overview]
Message-ID: <202509101705.92474D66@keescook> (raw)
In-Reply-To: <65CF25F7-E9F5-41C8-9316-F7A461FD35D0@oracle.com>
On Tue, Sep 09, 2025 at 06:49:22PM +0000, Qing Zhao wrote:
>
> > On Sep 4, 2025, at 20:24, Kees Cook <kees@kernel.org> wrote:
> > +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?
I couldn't find a way to stop merging just using the attributes. I need
a way to directly associated indirect call sites with the typeid.
> > +
> > +- 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?
This bullet is speaking about the backend change to support the KCFI
check-call insn sequences:
+/* 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)
> Why the type-id attached as the attribute is not enough?
Doing the wrapping avoided needing to update multiple optimization passes
to check for the attribute. And it still needed a way to distinguish
between direct and indirect calls, so I need to wrap only the indirect
calls, where as the typeid attribute is for all functions for all typeid
needs, like preamble generation, etc.
> > +
> > +- 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.
Fixed.
> > +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. -:)
Oh! Wow, yeah, I totally missed this coding style requirement. Fixed.
> > +/* 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?
no_sanitize(“kcfi”) is strictly about whether call-site checking
is performed within the function. It is not used to mark a function as
not being the target of a KCFI call.
> > +/* 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.
I understand GCC code style indentation to be "leading spans of 8 spaces
should be replaced with a tab character". This is what I followed:
first line indents to column 6, so 6 spaces. Second line indents to
column 8, so 1 tab:
SSSSSSif (TREE_CODE (value) == INTEGER_CST)
Treturn (uint32_t) TREE_INT_CST_LOW (value);
This seems to match everywhere else? Randomly picking line get_section()
from varasm.cc, I see the same:
if (not_existing)
internal_error ("section already exists: %qs", name);
> > + /* 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.
Oops, yes, thank you. Fixed.
What is the right tool for me to run to check for these kinds of code
style glitches? contrib/check_GNU_style.py doesn't report anything. Oh!
It takes _patches_ not _files_. The .sh version specifies "patch" in the
help usage. Okay, I will get this all passing cleanly.
> > +/* 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))
> > + {
> > + 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,
The attribute is attached during IPA. This is run before that, but as I
mentioned, this is the call-site handling, and the IPA pass is for
globally associating a type-id to the function for all other uses
(preambles, weak symbols, etc).
> > + // 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?
Based on my understanding of the requirements for GIMPLE here is that I
needed a cast between the original and the wrapper, and an assignment
for SSA. It's converting the call like:
Original: result = fn(arg1, arg2)
Becomes: result = wrapper(arg1, arg2, type_id)
I'm open to whatever alternative is needed here. I tried to capture the
merging issue with gcc/testsuite/gcc.dg/kcfi/kcfi-call-sharing.c
My other test methodology is "does Linux boot?" ;)
--
Kees Cook
next prev parent reply other threads:[~2025-09-11 3:05 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-05 0:24 [PATCH v2 0/7] Introduce Kernel Control Flow Integrity ABI [PR107048] Kees Cook
2025-09-05 0:24 ` [PATCH v2 1/7] mangle: Introduce C typeinfo mangling API Kees Cook
2025-09-05 0:50 ` Andrew Pinski
2025-09-05 1:09 ` Kees Cook
2025-09-05 0:24 ` [PATCH v2 2/7] kcfi: Add core Kernel Control Flow Integrity infrastructure Kees Cook
2025-09-05 8:51 ` Peter Zijlstra
2025-09-05 16:19 ` Kees Cook
2025-09-08 15:32 ` Peter Zijlstra
2025-09-08 21:55 ` Kees Cook
2025-09-09 18:49 ` Qing Zhao
2025-09-11 3:05 ` Kees Cook [this message]
2025-09-11 7:29 ` Peter Zijlstra
2025-09-12 6:20 ` Kees Cook
2025-09-11 15:04 ` Qing Zhao
2025-09-12 7:32 ` Kees Cook
2025-09-12 14:01 ` Qing Zhao
2025-09-13 6:29 ` Kees Cook
2025-09-05 0:24 ` [PATCH v2 3/7] x86: Add x86_64 Kernel Control Flow Integrity implementation Kees Cook
2025-09-05 0:24 ` [PATCH v2 4/7] aarch64: Add AArch64 " Kees Cook
2025-09-05 0:24 ` [PATCH v2 5/7] arm: Add ARM 32-bit " Kees Cook
2025-09-11 7:49 ` Ard Biesheuvel
2025-09-12 9:03 ` Kees Cook
2025-09-12 9:08 ` Kees Cook
2025-09-12 9:43 ` Ard Biesheuvel
2025-09-12 19:01 ` Kees Cook
2025-09-05 0:24 ` [PATCH v2 6/7] riscv: Add RISC-V " Kees Cook
2025-09-16 3:40 ` Jeff Law
2025-09-16 6:04 ` Kees Cook
2025-10-01 0:56 ` Jeff Law
2025-09-05 0:24 ` [PATCH v2 7/7] kcfi: Add regression test suite Kees Cook
2025-09-05 7:06 ` Jakub Jelinek
2025-09-05 17:15 ` Kees Cook
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=202509101705.92474D66@keescook \
--to=kees@kernel.org \
--cc=andrew@sifive.com \
--cc=ashimida.1990@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=hubicka@ucw.cz \
--cc=jim.wilson.gcc@gmail.com \
--cc=joao@overdrivepizza.com \
--cc=josmyers@redhat.com \
--cc=kito.cheng@gmail.com \
--cc=kyrylo.tkachov@arm.com \
--cc=linux-hardening@vger.kernel.org \
--cc=marcus.shawcroft@arm.com \
--cc=morbo@google.com \
--cc=nathan@kernel.org \
--cc=palmer@dabbelt.com \
--cc=peterz@infradead.org \
--cc=pinskia@gmail.com \
--cc=qing.zhao@oracle.com \
--cc=rcvalle@google.com \
--cc=rguenther@suse.de \
--cc=richard.earnshaw@arm.com \
--cc=richard.sandiford@arm.com \
--cc=samitolvanen@google.com \
/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.