diff mbox series

[1/2] cfi: add CONFIG_CFI_ICALL_NORMALIZE_INTEGERS

Message ID 20240730-kcfi-v1-1-bbb948752a30@google.com (mailing list archive)
State New
Headers show
Series Rust KCFI support | expand

Commit Message

Alice Ryhl July 30, 2024, 9:40 a.m. UTC
Introduce a Kconfig option for enabling the experimental option to
normalize integer types. This ensures that integer types of the same
size and signedness are considered compatible by the Control Flow
Integrity sanitizer.

This option exists for compatibility with Rust, as C and Rust do not
have the same set of integer types. There are cases where C has two
different integer types of the same size and alignment, but Rust only
has one integer type of that size and alignment. When Rust calls into
C functions using such types in their signature, this results in CFI
failures.

This patch introduces a dedicated option for this because it is
undesirable to have CONFIG_RUST affect CC_FLAGS in this way.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
 Makefile     |  3 +++
 arch/Kconfig | 11 +++++++++++
 2 files changed, 14 insertions(+)

Comments

Alice Ryhl July 30, 2024, 9:51 a.m. UTC | #1
On Tue, Jul 30, 2024 at 11:40 AM Alice Ryhl <aliceryhl@google.com> wrote:
>
> Introduce a Kconfig option for enabling the experimental option to
> normalize integer types. This ensures that integer types of the same
> size and signedness are considered compatible by the Control Flow
> Integrity sanitizer.
>
> This option exists for compatibility with Rust, as C and Rust do not
> have the same set of integer types. There are cases where C has two
> different integer types of the same size and alignment, but Rust only
> has one integer type of that size and alignment. When Rust calls into
> C functions using such types in their signature, this results in CFI
> failures.

This should say signedness where it says alignment.

Alice
Peter Zijlstra July 30, 2024, 10:28 a.m. UTC | #2
On Tue, Jul 30, 2024 at 09:40:11AM +0000, Alice Ryhl wrote:
> Introduce a Kconfig option for enabling the experimental option to
> normalize integer types. This ensures that integer types of the same
> size and signedness are considered compatible by the Control Flow
> Integrity sanitizer.
> 
> This option exists for compatibility with Rust, as C and Rust do not
> have the same set of integer types. There are cases where C has two
> different integer types of the same size and alignment, but Rust only
> has one integer type of that size and alignment. When Rust calls into
> C functions using such types in their signature, this results in CFI
> failures.
> 
> This patch introduces a dedicated option for this because it is
> undesirable to have CONFIG_RUST affect CC_FLAGS in this way.

To be clear, any code compiled with this is incompatible with code
compiled without this, as the function signatures will differ, right?

Specifically, it will map things like 'unsigned long long' and 'unsigned
long' -- which are both u64 on LP64 targets to the same 'type', right?

I suppose it has been decided the security impact of this change is
minimal?

All in all, there is very little actual information provided here.

> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
>  Makefile     |  3 +++
>  arch/Kconfig | 11 +++++++++++
>  2 files changed, 14 insertions(+)
> 
> diff --git a/Makefile b/Makefile
> index 2b5f9f098b6f..484c6900337e 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -952,6 +952,9 @@ endif
>  
>  ifdef CONFIG_CFI_CLANG
>  CC_FLAGS_CFI	:= -fsanitize=kcfi
> +ifdef CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
> +	CC_FLAGS_CFI	+= -fsanitize-cfi-icall-experimental-normalize-integers
> +endif
>  KBUILD_CFLAGS	+= $(CC_FLAGS_CFI)
>  export CC_FLAGS_CFI
>  endif
> diff --git a/arch/Kconfig b/arch/Kconfig
> index 975dd22a2dbd..f6ecb15cb8ba 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -826,6 +826,17 @@ config CFI_CLANG
>  
>  	    https://clang.llvm.org/docs/ControlFlowIntegrity.html
>  
> +config CFI_ICALL_NORMALIZE_INTEGERS
> +	bool "Normalize CFI tags for integers"
> +	depends on CFI_CLANG
> +	depends on $(cc-option,-fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers)
> +	help
> +	  This option normalizes the CFI tags for integer types so that all
> +	  integer types of the same size and signedness receive the same CFI
> +	  tag.
> +
> +	  This option is necessary for using CFI with Rust. If unsure, say N.
> +
>  config CFI_PERMISSIVE
>  	bool "Use CFI in permissive mode"
>  	depends on CFI_CLANG
> 
> -- 
> 2.46.0.rc1.232.g9752f9e123-goog
>
Miguel Ojeda July 30, 2024, 11:38 a.m. UTC | #3
On Tue, Jul 30, 2024 at 11:40 AM Alice Ryhl <aliceryhl@google.com> wrote:
>
> Introduce a Kconfig option for enabling the experimental option to
> normalize integer types. This ensures that integer types of the same
> size and signedness are considered compatible by the Control Flow
> Integrity sanitizer.
>
> This option exists for compatibility with Rust, as C and Rust do not
> have the same set of integer types. There are cases where C has two
> different integer types of the same size and alignment, but Rust only
> has one integer type of that size and alignment. When Rust calls into
> C functions using such types in their signature, this results in CFI
> failures.
>
> This patch introduces a dedicated option for this because it is
> undesirable to have CONFIG_RUST affect CC_FLAGS in this way.

Is there any case where we would want CFI_ICALL_NORMALIZE_INTEGERS
when Rust is not enabled, then? If not, is the idea here to make this
an explicit extra question in the config before enabling Rust? Or why
wouldn't it be done automatically?

Thanks!

Cheers,
Miguel
Peter Zijlstra July 30, 2024, 12:13 p.m. UTC | #4
On Tue, Jul 30, 2024 at 01:38:33PM +0200, Miguel Ojeda wrote:
> On Tue, Jul 30, 2024 at 11:40 AM Alice Ryhl <aliceryhl@google.com> wrote:
> >
> > Introduce a Kconfig option for enabling the experimental option to
> > normalize integer types. This ensures that integer types of the same
> > size and signedness are considered compatible by the Control Flow
> > Integrity sanitizer.
> >
> > This option exists for compatibility with Rust, as C and Rust do not
> > have the same set of integer types. There are cases where C has two
> > different integer types of the same size and alignment, but Rust only
> > has one integer type of that size and alignment. When Rust calls into
> > C functions using such types in their signature, this results in CFI
> > failures.
> >
> > This patch introduces a dedicated option for this because it is
> > undesirable to have CONFIG_RUST affect CC_FLAGS in this way.
> 
> Is there any case where we would want CFI_ICALL_NORMALIZE_INTEGERS
> when Rust is not enabled, then? If not, is the idea here to make this
> an explicit extra question in the config before enabling Rust? Or why
> wouldn't it be done automatically?

I suspect CFI_ICALL_NORMALIZE_INTEGERS breaks ABI, then again, Linux
doesn't promise or preserve ABI except for the SYSCALL layer. So yeah,
meh.
Sami Tolvanen July 30, 2024, 3:19 p.m. UTC | #5
On Tue, Jul 30, 2024 at 3:29 AM Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Tue, Jul 30, 2024 at 09:40:11AM +0000, Alice Ryhl wrote:
> > Introduce a Kconfig option for enabling the experimental option to
> > normalize integer types. This ensures that integer types of the same
> > size and signedness are considered compatible by the Control Flow
> > Integrity sanitizer.
> >
> > This option exists for compatibility with Rust, as C and Rust do not
> > have the same set of integer types. There are cases where C has two
> > different integer types of the same size and alignment, but Rust only
> > has one integer type of that size and alignment. When Rust calls into
> > C functions using such types in their signature, this results in CFI
> > failures.
> >
> > This patch introduces a dedicated option for this because it is
> > undesirable to have CONFIG_RUST affect CC_FLAGS in this way.
>
> To be clear, any code compiled with this is incompatible with code
> compiled without this, as the function signatures will differ, right?
>
> Specifically, it will map things like 'unsigned long long' and 'unsigned
> long' -- which are both u64 on LP64 targets to the same 'type', right?
>
> I suppose it has been decided the security impact of this change is
> minimal?

I looked into this last year, and integer normalization reduced the
number of unique type hashes in the kernel by ~1%, which should be
fine.

Sami
Peter Zijlstra July 30, 2024, 4:04 p.m. UTC | #6
On Tue, Jul 30, 2024 at 08:19:13AM -0700, Sami Tolvanen wrote:
> On Tue, Jul 30, 2024 at 3:29 AM Peter Zijlstra <peterz@infradead.org> wrote:
> >
> > On Tue, Jul 30, 2024 at 09:40:11AM +0000, Alice Ryhl wrote:
> > > Introduce a Kconfig option for enabling the experimental option to
> > > normalize integer types. This ensures that integer types of the same
> > > size and signedness are considered compatible by the Control Flow
> > > Integrity sanitizer.
> > >
> > > This option exists for compatibility with Rust, as C and Rust do not
> > > have the same set of integer types. There are cases where C has two
> > > different integer types of the same size and alignment, but Rust only
> > > has one integer type of that size and alignment. When Rust calls into
> > > C functions using such types in their signature, this results in CFI
> > > failures.
> > >
> > > This patch introduces a dedicated option for this because it is
> > > undesirable to have CONFIG_RUST affect CC_FLAGS in this way.
> >
> > To be clear, any code compiled with this is incompatible with code
> > compiled without this, as the function signatures will differ, right?
> >
> > Specifically, it will map things like 'unsigned long long' and 'unsigned
> > long' -- which are both u64 on LP64 targets to the same 'type', right?
> >
> > I suppose it has been decided the security impact of this change is
> > minimal?
> 
> I looked into this last year, and integer normalization reduced the
> number of unique type hashes in the kernel by ~1%, which should be
> fine.

Right, I didn't actually expect it to matter much either, but it
would've made good Changelog content.
Alice Ryhl July 30, 2024, 4:10 p.m. UTC | #7
On Tue, Jul 30, 2024 at 12:29 PM Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Tue, Jul 30, 2024 at 09:40:11AM +0000, Alice Ryhl wrote:
> > Introduce a Kconfig option for enabling the experimental option to
> > normalize integer types. This ensures that integer types of the same
> > size and signedness are considered compatible by the Control Flow
> > Integrity sanitizer.
> >
> > This option exists for compatibility with Rust, as C and Rust do not
> > have the same set of integer types. There are cases where C has two
> > different integer types of the same size and alignment, but Rust only
> > has one integer type of that size and alignment. When Rust calls into
> > C functions using such types in their signature, this results in CFI
> > failures.
> >
> > This patch introduces a dedicated option for this because it is
> > undesirable to have CONFIG_RUST affect CC_FLAGS in this way.
>
> To be clear, any code compiled with this is incompatible with code
> compiled without this, as the function signatures will differ, right?

That's correct.

> Specifically, it will map things like 'unsigned long long' and 'unsigned
> long' -- which are both u64 on LP64 targets to the same 'type', right?

That's correct.

> I suppose it has been decided the security impact of this change is
> minimal?

Yeah, see Sami's response.

> All in all, there is very little actual information provided here.

I'll make sure to include this info in the commit message of v2.

Alice
Alice Ryhl July 30, 2024, 4:10 p.m. UTC | #8
On Tue, Jul 30, 2024 at 1:38 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Tue, Jul 30, 2024 at 11:40 AM Alice Ryhl <aliceryhl@google.com> wrote:
> >
> > Introduce a Kconfig option for enabling the experimental option to
> > normalize integer types. This ensures that integer types of the same
> > size and signedness are considered compatible by the Control Flow
> > Integrity sanitizer.
> >
> > This option exists for compatibility with Rust, as C and Rust do not
> > have the same set of integer types. There are cases where C has two
> > different integer types of the same size and alignment, but Rust only
> > has one integer type of that size and alignment. When Rust calls into
> > C functions using such types in their signature, this results in CFI
> > failures.
> >
> > This patch introduces a dedicated option for this because it is
> > undesirable to have CONFIG_RUST affect CC_FLAGS in this way.
>
> Is there any case where we would want CFI_ICALL_NORMALIZE_INTEGERS
> when Rust is not enabled, then? If not, is the idea here to make this
> an explicit extra question in the config before enabling Rust? Or why
> wouldn't it be done automatically?

I'm adding this flag to make the bringup process for RUST easier.

I'm working on enabling RUST in a new branch. We're eventually going
to have both RUST and CFI_ICALL_NORMALIZE_INTEGERS enabled in our
build, but the path to getting there is complex and we would like to
turn on CFI_ICALL_NORMALIZE_INTEGERS first, and then turn on RUST
later. Both options are non-trivial to turn on and I want to
disentangle them.

Alice
Miguel Ojeda July 30, 2024, 6:01 p.m. UTC | #9
On Tue, Jul 30, 2024 at 6:10 PM Alice Ryhl <aliceryhl@google.com> wrote:
>
> I'm adding this flag to make the bringup process for RUST easier.
>
> I'm working on enabling RUST in a new branch. We're eventually going
> to have both RUST and CFI_ICALL_NORMALIZE_INTEGERS enabled in our
> build, but the path to getting there is complex and we would like to
> turn on CFI_ICALL_NORMALIZE_INTEGERS first, and then turn on RUST
> later. Both options are non-trivial to turn on and I want to
> disentangle them.

Would it be useful for other users/distros to do that two-stage
approach as well?

In other words, if the intended end state is that everybody should
enable this if Rust is enabled, and nobody should enable it if they
don't care about Rust, then we should add this only if you think
others will also need to do this step by step. The option or commit
message could ideally explain more about this need/use case.

Cheers,
Miguel
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index 2b5f9f098b6f..484c6900337e 100644
--- a/Makefile
+++ b/Makefile
@@ -952,6 +952,9 @@  endif
 
 ifdef CONFIG_CFI_CLANG
 CC_FLAGS_CFI	:= -fsanitize=kcfi
+ifdef CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
+	CC_FLAGS_CFI	+= -fsanitize-cfi-icall-experimental-normalize-integers
+endif
 KBUILD_CFLAGS	+= $(CC_FLAGS_CFI)
 export CC_FLAGS_CFI
 endif
diff --git a/arch/Kconfig b/arch/Kconfig
index 975dd22a2dbd..f6ecb15cb8ba 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -826,6 +826,17 @@  config CFI_CLANG
 
 	    https://clang.llvm.org/docs/ControlFlowIntegrity.html
 
+config CFI_ICALL_NORMALIZE_INTEGERS
+	bool "Normalize CFI tags for integers"
+	depends on CFI_CLANG
+	depends on $(cc-option,-fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers)
+	help
+	  This option normalizes the CFI tags for integer types so that all
+	  integer types of the same size and signedness receive the same CFI
+	  tag.
+
+	  This option is necessary for using CFI with Rust. If unsure, say N.
+
 config CFI_PERMISSIVE
 	bool "Use CFI in permissive mode"
 	depends on CFI_CLANG