* [PATCH 1/4] arm64: Introduce esr_is_ubsan_brk()
2025-04-16 18:04 [PATCH 0/4] KVM: arm64: UBSAN at EL2 Mostafa Saleh
@ 2025-04-16 18:04 ` Mostafa Saleh
2025-04-16 18:04 ` [PATCH 2/4] ubsan: Remove regs from report_ubsan_failure() Mostafa Saleh
` (3 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Mostafa Saleh @ 2025-04-16 18:04 UTC (permalink / raw)
To: kvmarm, kasan-dev, linux-hardening, linux-kbuild, linux-kernel,
linux-arm-kernel
Cc: will, maz, oliver.upton, broonie, catalin.marinas, tglx, mingo,
bp, dave.hansen, x86, hpa, kees, elver, andreyknvl, ryabinin.a.a,
akpm, yuzenghui, suzuki.poulose, joey.gouly, masahiroy, nathan,
nicolas.schier, Mostafa Saleh
Soon, KVM is going to use this logic for hypervisor panics,
so add it in a wrapper that can be used by the hypervisor exit
handler to decode hyp panics.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
arch/arm64/include/asm/esr.h | 5 +++++
arch/arm64/kernel/traps.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index e4f77757937e..350f02bf437d 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -440,6 +440,11 @@ static inline bool esr_is_cfi_brk(unsigned long esr)
(esr_brk_comment(esr) & ~CFI_BRK_IMM_MASK) == CFI_BRK_IMM_BASE;
}
+static inline bool esr_is_ubsan_brk(unsigned long esr)
+{
+ return (esr_brk_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM;
+}
+
static inline bool esr_fsc_is_translation_fault(unsigned long esr)
{
esr = esr & ESR_ELx_FSC;
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 529cff825531..224f927ac8af 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -1145,7 +1145,7 @@ int __init early_brk64(unsigned long addr, unsigned long esr,
return kasan_handler(regs, esr) != DBG_HOOK_HANDLED;
#endif
#ifdef CONFIG_UBSAN_TRAP
- if ((esr_brk_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM)
+ if (esr_is_ubsan_brk(esr))
return ubsan_handler(regs, esr) != DBG_HOOK_HANDLED;
#endif
return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
--
2.49.0.604.gff1f9ca942-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 2/4] ubsan: Remove regs from report_ubsan_failure()
2025-04-16 18:04 [PATCH 0/4] KVM: arm64: UBSAN at EL2 Mostafa Saleh
2025-04-16 18:04 ` [PATCH 1/4] arm64: Introduce esr_is_ubsan_brk() Mostafa Saleh
@ 2025-04-16 18:04 ` Mostafa Saleh
2025-04-16 19:47 ` Kees Cook
2025-04-16 18:04 ` [PATCH 3/4] KVM: arm64: Introduce CONFIG_UBSAN_KVM_EL2 Mostafa Saleh
` (2 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Mostafa Saleh @ 2025-04-16 18:04 UTC (permalink / raw)
To: kvmarm, kasan-dev, linux-hardening, linux-kbuild, linux-kernel,
linux-arm-kernel
Cc: will, maz, oliver.upton, broonie, catalin.marinas, tglx, mingo,
bp, dave.hansen, x86, hpa, kees, elver, andreyknvl, ryabinin.a.a,
akpm, yuzenghui, suzuki.poulose, joey.gouly, masahiroy, nathan,
nicolas.schier, Mostafa Saleh
report_ubsan_failure() doesn't use argument regs, and soon it will
be called from the hypervisor context were regs are not available.
So, remove the unused argument.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
arch/arm64/kernel/traps.c | 2 +-
arch/x86/kernel/traps.c | 2 +-
include/linux/ubsan.h | 4 ++--
lib/ubsan.c | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 224f927ac8af..9bfa5c944379 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -1118,7 +1118,7 @@ static struct break_hook kasan_break_hook = {
#ifdef CONFIG_UBSAN_TRAP
static int ubsan_handler(struct pt_regs *regs, unsigned long esr)
{
- die(report_ubsan_failure(regs, esr & UBSAN_BRK_MASK), regs, esr);
+ die(report_ubsan_failure(esr & UBSAN_BRK_MASK), regs, esr);
return DBG_HOOK_HANDLED;
}
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 9f88b8a78e50..4b5a7a1a8dde 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -351,7 +351,7 @@ static noinstr bool handle_bug(struct pt_regs *regs)
case BUG_UD1_UBSAN:
if (IS_ENABLED(CONFIG_UBSAN_TRAP)) {
pr_crit("%s at %pS\n",
- report_ubsan_failure(regs, ud_imm),
+ report_ubsan_failure(ud_imm),
(void *)regs->ip);
}
break;
diff --git a/include/linux/ubsan.h b/include/linux/ubsan.h
index d8219cbe09ff..c843816f5f68 100644
--- a/include/linux/ubsan.h
+++ b/include/linux/ubsan.h
@@ -3,9 +3,9 @@
#define _LINUX_UBSAN_H
#ifdef CONFIG_UBSAN_TRAP
-const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type);
+const char *report_ubsan_failure(u32 check_type);
#else
-static inline const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type)
+static inline const char *report_ubsan_failure(u32 check_type)
{
return NULL;
}
diff --git a/lib/ubsan.c b/lib/ubsan.c
index cdc1d31c3821..17993727fc96 100644
--- a/lib/ubsan.c
+++ b/lib/ubsan.c
@@ -25,7 +25,7 @@
* The mappings of struct SanitizerKind (the -fsanitize=xxx args) to
* enum SanitizerHandler (the traps) in Clang is in clang/lib/CodeGen/.
*/
-const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type)
+const char *report_ubsan_failure(u32 check_type)
{
switch (check_type) {
#ifdef CONFIG_UBSAN_BOUNDS
--
2.49.0.604.gff1f9ca942-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 2/4] ubsan: Remove regs from report_ubsan_failure()
2025-04-16 18:04 ` [PATCH 2/4] ubsan: Remove regs from report_ubsan_failure() Mostafa Saleh
@ 2025-04-16 19:47 ` Kees Cook
0 siblings, 0 replies; 9+ messages in thread
From: Kees Cook @ 2025-04-16 19:47 UTC (permalink / raw)
To: Mostafa Saleh
Cc: kvmarm, kasan-dev, linux-hardening, linux-kbuild, linux-kernel,
linux-arm-kernel, will, maz, oliver.upton, broonie,
catalin.marinas, tglx, mingo, bp, dave.hansen, x86, hpa, elver,
andreyknvl, ryabinin.a.a, akpm, yuzenghui, suzuki.poulose,
joey.gouly, masahiroy, nathan, nicolas.schier
On Wed, Apr 16, 2025 at 06:04:32PM +0000, Mostafa Saleh wrote:
> report_ubsan_failure() doesn't use argument regs, and soon it will
> be called from the hypervisor context were regs are not available.
> So, remove the unused argument.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
Funny. I wonder why I put that argument in there? If we ever need it
again, we can just make it conditional (and let the hypervisor pass
NULL).
Acked-by: Kees Cook <kees@kernel.org>
--
Kees Cook
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/4] KVM: arm64: Introduce CONFIG_UBSAN_KVM_EL2
2025-04-16 18:04 [PATCH 0/4] KVM: arm64: UBSAN at EL2 Mostafa Saleh
2025-04-16 18:04 ` [PATCH 1/4] arm64: Introduce esr_is_ubsan_brk() Mostafa Saleh
2025-04-16 18:04 ` [PATCH 2/4] ubsan: Remove regs from report_ubsan_failure() Mostafa Saleh
@ 2025-04-16 18:04 ` Mostafa Saleh
2025-04-16 19:54 ` Kees Cook
2025-04-16 18:04 ` [PATCH 4/4] KVM: arm64: Handle UBSAN faults Mostafa Saleh
2025-04-16 19:56 ` [PATCH 0/4] KVM: arm64: UBSAN at EL2 Kees Cook
4 siblings, 1 reply; 9+ messages in thread
From: Mostafa Saleh @ 2025-04-16 18:04 UTC (permalink / raw)
To: kvmarm, kasan-dev, linux-hardening, linux-kbuild, linux-kernel,
linux-arm-kernel
Cc: will, maz, oliver.upton, broonie, catalin.marinas, tglx, mingo,
bp, dave.hansen, x86, hpa, kees, elver, andreyknvl, ryabinin.a.a,
akpm, yuzenghui, suzuki.poulose, joey.gouly, masahiroy, nathan,
nicolas.schier, Mostafa Saleh
Add a new Kconfig CONFIG_UBSAN_KVM_EL2 for KVM which enables
UBSAN for EL2 code (in protected/nvhe/hvhe) modes.
This will re-use the same checks enabled for the kernel for
the hypervisor. The only difference is that for EL2 it always
emits a "brk" instead of implementing hooks as the hypervisor
can't print reports.
The KVM code will re-use the same code for the kernel
"report_ubsan_failure()" so #ifdefs are changed to also have this
code for CONFIG_UBSAN_KVM_EL2
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
arch/arm64/kvm/hyp/nvhe/Makefile | 6 ++++++
include/linux/ubsan.h | 2 +-
lib/Kconfig.ubsan | 9 +++++++++
lib/ubsan.c | 6 ++++--
scripts/Makefile.ubsan | 5 ++++-
5 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index b43426a493df..cbe7e12752bc 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -99,3 +99,9 @@ KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS), $(KBUILD_CFLAG
# causes a build failure. Remove profile optimization flags.
KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%, $(KBUILD_CFLAGS))
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
+
+ifeq ($(CONFIG_UBSAN_KVM_EL2),y)
+UBSAN_SANITIZE := y
+# Always use brk and not hooks
+ccflags-y += $(CFLAGS_UBSAN_FOR_TRAP)
+endif
diff --git a/include/linux/ubsan.h b/include/linux/ubsan.h
index c843816f5f68..3ab8d38aedb8 100644
--- a/include/linux/ubsan.h
+++ b/include/linux/ubsan.h
@@ -2,7 +2,7 @@
#ifndef _LINUX_UBSAN_H
#define _LINUX_UBSAN_H
-#ifdef CONFIG_UBSAN_TRAP
+#if defined(CONFIG_UBSAN_TRAP) || defined(CONFIG_UBSAN_KVM_EL2)
const char *report_ubsan_failure(u32 check_type);
#else
static inline const char *report_ubsan_failure(u32 check_type)
diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan
index 4216b3a4ff21..3878858eb473 100644
--- a/lib/Kconfig.ubsan
+++ b/lib/Kconfig.ubsan
@@ -166,4 +166,13 @@ config TEST_UBSAN
This is a test module for UBSAN.
It triggers various undefined behavior, and detect it.
+config UBSAN_KVM_EL2
+ bool "UBSAN for KVM code at EL2"
+ depends on ARM64
+ help
+ Enable UBSAN when running on ARM64 with KVM in a split mode
+ (nvhe/hvhe/protected) for the hypervisor code running in EL2.
+ In this mode, any UBSAN violation in EL2 would panic the kernel
+ and information similar to UBSAN_TRAP would be printed.
+
endif # if UBSAN
diff --git a/lib/ubsan.c b/lib/ubsan.c
index 17993727fc96..a6ca235dd714 100644
--- a/lib/ubsan.c
+++ b/lib/ubsan.c
@@ -19,7 +19,7 @@
#include "ubsan.h"
-#ifdef CONFIG_UBSAN_TRAP
+#if defined(CONFIG_UBSAN_TRAP) || defined(CONFIG_UBSAN_KVM_EL2)
/*
* Only include matches for UBSAN checks that are actually compiled in.
* The mappings of struct SanitizerKind (the -fsanitize=xxx args) to
@@ -97,7 +97,9 @@ const char *report_ubsan_failure(u32 check_type)
}
}
-#else
+#endif
+
+#ifndef CONFIG_UBSAN_TRAP
static const char * const type_check_kinds[] = {
"load of",
"store to",
diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan
index 9e35198edbf0..68af6830af0f 100644
--- a/scripts/Makefile.ubsan
+++ b/scripts/Makefile.ubsan
@@ -1,5 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
+#Shared with KVM/arm64
+export CFLAGS_UBSAN_FOR_TRAP := $(call cc-option,-fsanitize-trap=undefined,-fsanitize-undefined-trap-on-error)
+
# Enable available and selected UBSAN features.
ubsan-cflags-$(CONFIG_UBSAN_ALIGNMENT) += -fsanitize=alignment
ubsan-cflags-$(CONFIG_UBSAN_BOUNDS_STRICT) += -fsanitize=bounds-strict
@@ -10,7 +13,7 @@ ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero
ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable
ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool
ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum
-ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(call cc-option,-fsanitize-trap=undefined,-fsanitize-undefined-trap-on-error)
+ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(CFLAGS_UBSAN_FOR_TRAP)
export CFLAGS_UBSAN := $(ubsan-cflags-y)
--
2.49.0.604.gff1f9ca942-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 3/4] KVM: arm64: Introduce CONFIG_UBSAN_KVM_EL2
2025-04-16 18:04 ` [PATCH 3/4] KVM: arm64: Introduce CONFIG_UBSAN_KVM_EL2 Mostafa Saleh
@ 2025-04-16 19:54 ` Kees Cook
2025-04-25 17:30 ` Mostafa Saleh
0 siblings, 1 reply; 9+ messages in thread
From: Kees Cook @ 2025-04-16 19:54 UTC (permalink / raw)
To: Mostafa Saleh
Cc: kvmarm, kasan-dev, linux-hardening, linux-kbuild, linux-kernel,
linux-arm-kernel, will, maz, oliver.upton, broonie,
catalin.marinas, tglx, mingo, bp, dave.hansen, x86, hpa, elver,
andreyknvl, ryabinin.a.a, akpm, yuzenghui, suzuki.poulose,
joey.gouly, masahiroy, nathan, nicolas.schier
On Wed, Apr 16, 2025 at 06:04:33PM +0000, Mostafa Saleh wrote:
> Add a new Kconfig CONFIG_UBSAN_KVM_EL2 for KVM which enables
> UBSAN for EL2 code (in protected/nvhe/hvhe) modes.
> This will re-use the same checks enabled for the kernel for
> the hypervisor. The only difference is that for EL2 it always
> emits a "brk" instead of implementing hooks as the hypervisor
> can't print reports.
>
> The KVM code will re-use the same code for the kernel
> "report_ubsan_failure()" so #ifdefs are changed to also have this
> code for CONFIG_UBSAN_KVM_EL2
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> arch/arm64/kvm/hyp/nvhe/Makefile | 6 ++++++
> include/linux/ubsan.h | 2 +-
> lib/Kconfig.ubsan | 9 +++++++++
> lib/ubsan.c | 6 ++++--
> scripts/Makefile.ubsan | 5 ++++-
> 5 files changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
> index b43426a493df..cbe7e12752bc 100644
> --- a/arch/arm64/kvm/hyp/nvhe/Makefile
> +++ b/arch/arm64/kvm/hyp/nvhe/Makefile
> @@ -99,3 +99,9 @@ KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS), $(KBUILD_CFLAG
> # causes a build failure. Remove profile optimization flags.
> KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%, $(KBUILD_CFLAGS))
> KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
> +
> +ifeq ($(CONFIG_UBSAN_KVM_EL2),y)
> +UBSAN_SANITIZE := y
> +# Always use brk and not hooks
> +ccflags-y += $(CFLAGS_UBSAN_FOR_TRAP)
> +endif
> diff --git a/include/linux/ubsan.h b/include/linux/ubsan.h
> index c843816f5f68..3ab8d38aedb8 100644
> --- a/include/linux/ubsan.h
> +++ b/include/linux/ubsan.h
> @@ -2,7 +2,7 @@
> #ifndef _LINUX_UBSAN_H
> #define _LINUX_UBSAN_H
>
> -#ifdef CONFIG_UBSAN_TRAP
> +#if defined(CONFIG_UBSAN_TRAP) || defined(CONFIG_UBSAN_KVM_EL2)
> const char *report_ubsan_failure(u32 check_type);
> #else
> static inline const char *report_ubsan_failure(u32 check_type)
> diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan
> index 4216b3a4ff21..3878858eb473 100644
> --- a/lib/Kconfig.ubsan
> +++ b/lib/Kconfig.ubsan
> @@ -166,4 +166,13 @@ config TEST_UBSAN
> This is a test module for UBSAN.
> It triggers various undefined behavior, and detect it.
>
> +config UBSAN_KVM_EL2
> + bool "UBSAN for KVM code at EL2"
> + depends on ARM64
> + help
> + Enable UBSAN when running on ARM64 with KVM in a split mode
> + (nvhe/hvhe/protected) for the hypervisor code running in EL2.
> + In this mode, any UBSAN violation in EL2 would panic the kernel
> + and information similar to UBSAN_TRAP would be printed.
> +
> endif # if UBSAN
> diff --git a/lib/ubsan.c b/lib/ubsan.c
> index 17993727fc96..a6ca235dd714 100644
> --- a/lib/ubsan.c
> +++ b/lib/ubsan.c
> @@ -19,7 +19,7 @@
>
> #include "ubsan.h"
>
> -#ifdef CONFIG_UBSAN_TRAP
> +#if defined(CONFIG_UBSAN_TRAP) || defined(CONFIG_UBSAN_KVM_EL2)
> /*
> * Only include matches for UBSAN checks that are actually compiled in.
> * The mappings of struct SanitizerKind (the -fsanitize=xxx args) to
> @@ -97,7 +97,9 @@ const char *report_ubsan_failure(u32 check_type)
> }
> }
>
> -#else
> +#endif
> +
> +#ifndef CONFIG_UBSAN_TRAP
> static const char * const type_check_kinds[] = {
> "load of",
> "store to",
> diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan
> index 9e35198edbf0..68af6830af0f 100644
> --- a/scripts/Makefile.ubsan
> +++ b/scripts/Makefile.ubsan
> @@ -1,5 +1,8 @@
> # SPDX-License-Identifier: GPL-2.0
>
> +#Shared with KVM/arm64
Nitpick: Please add a space between "#" and "Shared", and end the line
with "."
> +export CFLAGS_UBSAN_FOR_TRAP := $(call cc-option,-fsanitize-trap=undefined,-fsanitize-undefined-trap-on-error)
> +
> # Enable available and selected UBSAN features.
> ubsan-cflags-$(CONFIG_UBSAN_ALIGNMENT) += -fsanitize=alignment
> ubsan-cflags-$(CONFIG_UBSAN_BOUNDS_STRICT) += -fsanitize=bounds-strict
> @@ -10,7 +13,7 @@ ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero
> ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable
> ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool
> ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum
> -ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(call cc-option,-fsanitize-trap=undefined,-fsanitize-undefined-trap-on-error)
> +ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(CFLAGS_UBSAN_FOR_TRAP)
Another minor style request: please name this "CFLAGS_UBSAN_TRAP"
(nothing else in Kconfig uses "FOR" like this, and leaving it off sounds
more declarative).
>
> export CFLAGS_UBSAN := $(ubsan-cflags-y)
Otherwise, yes, looks good.
--
Kees Cook
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 3/4] KVM: arm64: Introduce CONFIG_UBSAN_KVM_EL2
2025-04-16 19:54 ` Kees Cook
@ 2025-04-25 17:30 ` Mostafa Saleh
0 siblings, 0 replies; 9+ messages in thread
From: Mostafa Saleh @ 2025-04-25 17:30 UTC (permalink / raw)
To: Kees Cook
Cc: kvmarm, kasan-dev, linux-hardening, linux-kbuild, linux-kernel,
linux-arm-kernel, will, maz, oliver.upton, broonie,
catalin.marinas, tglx, mingo, bp, dave.hansen, x86, hpa, elver,
andreyknvl, ryabinin.a.a, akpm, yuzenghui, suzuki.poulose,
joey.gouly, masahiroy, nathan, nicolas.schier
On Wed, Apr 16, 2025 at 12:54:21PM -0700, Kees Cook wrote:
> On Wed, Apr 16, 2025 at 06:04:33PM +0000, Mostafa Saleh wrote:
> > Add a new Kconfig CONFIG_UBSAN_KVM_EL2 for KVM which enables
> > UBSAN for EL2 code (in protected/nvhe/hvhe) modes.
> > This will re-use the same checks enabled for the kernel for
> > the hypervisor. The only difference is that for EL2 it always
> > emits a "brk" instead of implementing hooks as the hypervisor
> > can't print reports.
> >
> > The KVM code will re-use the same code for the kernel
> > "report_ubsan_failure()" so #ifdefs are changed to also have this
> > code for CONFIG_UBSAN_KVM_EL2
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > arch/arm64/kvm/hyp/nvhe/Makefile | 6 ++++++
> > include/linux/ubsan.h | 2 +-
> > lib/Kconfig.ubsan | 9 +++++++++
> > lib/ubsan.c | 6 ++++--
> > scripts/Makefile.ubsan | 5 ++++-
> > 5 files changed, 24 insertions(+), 4 deletions(-)
> >
> > diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
> > index b43426a493df..cbe7e12752bc 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/Makefile
> > +++ b/arch/arm64/kvm/hyp/nvhe/Makefile
> > @@ -99,3 +99,9 @@ KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS), $(KBUILD_CFLAG
> > # causes a build failure. Remove profile optimization flags.
> > KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%, $(KBUILD_CFLAGS))
> > KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
> > +
> > +ifeq ($(CONFIG_UBSAN_KVM_EL2),y)
> > +UBSAN_SANITIZE := y
> > +# Always use brk and not hooks
> > +ccflags-y += $(CFLAGS_UBSAN_FOR_TRAP)
> > +endif
> > diff --git a/include/linux/ubsan.h b/include/linux/ubsan.h
> > index c843816f5f68..3ab8d38aedb8 100644
> > --- a/include/linux/ubsan.h
> > +++ b/include/linux/ubsan.h
> > @@ -2,7 +2,7 @@
> > #ifndef _LINUX_UBSAN_H
> > #define _LINUX_UBSAN_H
> >
> > -#ifdef CONFIG_UBSAN_TRAP
> > +#if defined(CONFIG_UBSAN_TRAP) || defined(CONFIG_UBSAN_KVM_EL2)
> > const char *report_ubsan_failure(u32 check_type);
> > #else
> > static inline const char *report_ubsan_failure(u32 check_type)
> > diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan
> > index 4216b3a4ff21..3878858eb473 100644
> > --- a/lib/Kconfig.ubsan
> > +++ b/lib/Kconfig.ubsan
> > @@ -166,4 +166,13 @@ config TEST_UBSAN
> > This is a test module for UBSAN.
> > It triggers various undefined behavior, and detect it.
> >
> > +config UBSAN_KVM_EL2
> > + bool "UBSAN for KVM code at EL2"
> > + depends on ARM64
> > + help
> > + Enable UBSAN when running on ARM64 with KVM in a split mode
> > + (nvhe/hvhe/protected) for the hypervisor code running in EL2.
> > + In this mode, any UBSAN violation in EL2 would panic the kernel
> > + and information similar to UBSAN_TRAP would be printed.
> > +
> > endif # if UBSAN
> > diff --git a/lib/ubsan.c b/lib/ubsan.c
> > index 17993727fc96..a6ca235dd714 100644
> > --- a/lib/ubsan.c
> > +++ b/lib/ubsan.c
> > @@ -19,7 +19,7 @@
> >
> > #include "ubsan.h"
> >
> > -#ifdef CONFIG_UBSAN_TRAP
> > +#if defined(CONFIG_UBSAN_TRAP) || defined(CONFIG_UBSAN_KVM_EL2)
> > /*
> > * Only include matches for UBSAN checks that are actually compiled in.
> > * The mappings of struct SanitizerKind (the -fsanitize=xxx args) to
> > @@ -97,7 +97,9 @@ const char *report_ubsan_failure(u32 check_type)
> > }
> > }
> >
> > -#else
> > +#endif
> > +
> > +#ifndef CONFIG_UBSAN_TRAP
> > static const char * const type_check_kinds[] = {
> > "load of",
> > "store to",
> > diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan
> > index 9e35198edbf0..68af6830af0f 100644
> > --- a/scripts/Makefile.ubsan
> > +++ b/scripts/Makefile.ubsan
> > @@ -1,5 +1,8 @@
> > # SPDX-License-Identifier: GPL-2.0
> >
> > +#Shared with KVM/arm64
>
> Nitpick: Please add a space between "#" and "Shared", and end the line
> with "."
I will fix it in v2.
>
> > +export CFLAGS_UBSAN_FOR_TRAP := $(call cc-option,-fsanitize-trap=undefined,-fsanitize-undefined-trap-on-error)
> > +
> > # Enable available and selected UBSAN features.
> > ubsan-cflags-$(CONFIG_UBSAN_ALIGNMENT) += -fsanitize=alignment
> > ubsan-cflags-$(CONFIG_UBSAN_BOUNDS_STRICT) += -fsanitize=bounds-strict
> > @@ -10,7 +13,7 @@ ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero
> > ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable
> > ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool
> > ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum
> > -ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(call cc-option,-fsanitize-trap=undefined,-fsanitize-undefined-trap-on-error)
> > +ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(CFLAGS_UBSAN_FOR_TRAP)
>
> Another minor style request: please name this "CFLAGS_UBSAN_TRAP"
> (nothing else in Kconfig uses "FOR" like this, and leaving it off sounds
> more declarative).
I will fix it also in v2.
>
> >
> > export CFLAGS_UBSAN := $(ubsan-cflags-y)
>
> Otherwise, yes, looks good.
>
> --
> Kees Cook
Thanks,
Mostafa
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/4] KVM: arm64: Handle UBSAN faults
2025-04-16 18:04 [PATCH 0/4] KVM: arm64: UBSAN at EL2 Mostafa Saleh
` (2 preceding siblings ...)
2025-04-16 18:04 ` [PATCH 3/4] KVM: arm64: Introduce CONFIG_UBSAN_KVM_EL2 Mostafa Saleh
@ 2025-04-16 18:04 ` Mostafa Saleh
2025-04-16 19:56 ` [PATCH 0/4] KVM: arm64: UBSAN at EL2 Kees Cook
4 siblings, 0 replies; 9+ messages in thread
From: Mostafa Saleh @ 2025-04-16 18:04 UTC (permalink / raw)
To: kvmarm, kasan-dev, linux-hardening, linux-kbuild, linux-kernel,
linux-arm-kernel
Cc: will, maz, oliver.upton, broonie, catalin.marinas, tglx, mingo,
bp, dave.hansen, x86, hpa, kees, elver, andreyknvl, ryabinin.a.a,
akpm, yuzenghui, suzuki.poulose, joey.gouly, masahiroy, nathan,
nicolas.schier, Mostafa Saleh
As now UBSAN can be enabled, handle brk64 exits from UBSAN.
Re-use the decoding code from the kernel, and panic with
UBSAN message.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
arch/arm64/kvm/handle_exit.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index b73dc26bc44b..5c49540883e3 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -10,6 +10,7 @@
#include <linux/kvm.h>
#include <linux/kvm_host.h>
+#include <linux/ubsan.h>
#include <asm/esr.h>
#include <asm/exception.h>
@@ -474,6 +475,11 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr,
print_nvhe_hyp_panic("BUG", panic_addr);
} else if (IS_ENABLED(CONFIG_CFI_CLANG) && esr_is_cfi_brk(esr)) {
kvm_nvhe_report_cfi_failure(panic_addr);
+ } else if (IS_ENABLED(CONFIG_UBSAN_KVM_EL2) &&
+ ESR_ELx_EC(esr) == ESR_ELx_EC_BRK64 &&
+ esr_is_ubsan_brk(esr)) {
+ print_nvhe_hyp_panic(report_ubsan_failure(esr & UBSAN_BRK_MASK),
+ panic_addr);
} else {
print_nvhe_hyp_panic("panic", panic_addr);
}
--
2.49.0.604.gff1f9ca942-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 0/4] KVM: arm64: UBSAN at EL2
2025-04-16 18:04 [PATCH 0/4] KVM: arm64: UBSAN at EL2 Mostafa Saleh
` (3 preceding siblings ...)
2025-04-16 18:04 ` [PATCH 4/4] KVM: arm64: Handle UBSAN faults Mostafa Saleh
@ 2025-04-16 19:56 ` Kees Cook
4 siblings, 0 replies; 9+ messages in thread
From: Kees Cook @ 2025-04-16 19:56 UTC (permalink / raw)
To: Mostafa Saleh
Cc: kvmarm, kasan-dev, linux-hardening, linux-kbuild, linux-kernel,
linux-arm-kernel, will, maz, oliver.upton, broonie,
catalin.marinas, tglx, mingo, bp, dave.hansen, x86, hpa, elver,
andreyknvl, ryabinin.a.a, akpm, yuzenghui, suzuki.poulose,
joey.gouly, masahiroy, nathan, nicolas.schier
On Wed, Apr 16, 2025 at 06:04:30PM +0000, Mostafa Saleh wrote:
> Many of the sanitizers the kernel supports are disabled when running
> in EL2 with nvhe/hvhe/proctected modes, some of those are easier
> (and makes more sense) to integrate than others.
> Last year, kCFI support was added in [1]
>
> This patchset adds support for UBSAN in EL2.
> UBSAN can run in 2 modes:
> 1) “Normal” (CONFIG_UBSAN_TRAP=n): In this mode the compiler will
> do the UBSAN checks and insert some function calls in case of
> failures, it can provide more information(ex: what is the value of
> the out of bound) about the failures through those function arguments,
> and those functions(implemented in lib/ubsan.c) will print a report with
> such errors.
>
> 2) Trap (CONFIG_UBSAN_TRAP=y): This is a minimal mode, where similarly,
> the compiler will do the checks, but instead of doing function calls,
> it would do a “brk #imm” (for ARM64) with a unique code with the failure
> type, but without any extra information (ex: only print the out-bound line
> but not the index)
>
> For nvhe/hvhe/proctected modes, #2 would be suitable, as there is no way to
> print reports from EL2, so similarly to kCFI(even with permissive) it would
> cause the hypervisor to panic.
>
> But that means that for EL2 we need to compile the code with the same options
> as used by “CONFIG_UBSAN_TRAP” independently from the kernel config.
>
> This patch series adds a new KCONFIG for ARM64 to choose to enable UBSAN
> separately for the modes mentioned.
>
> The same logic decoding the kernel UBSAN is reused, so the messages from
> the hypervisor will look similar as:
> [ 29.215332] kvm [190]: nVHE hyp UBSAN: array index out of bounds at: [<ffff8000811f2344>] __kvm_nvhe_handle___pkvm_init_vm+0xa8/0xac!
>
> In this patch set, the same UBSAN options(for check types) are used for both
> EL1/EL2, although a case can be made to have separate options (leading to
> totally separate CFLAGS) if we want EL2 to be compiled with stricter checks
> for something as protected mode.
> However, re-using the current flags, makes code re-use easier for
> report_ubsan_failure() and Makefile.ubsan
>
> [1] https://lore.kernel.org/all/20240610063244.2828978-1-ptosi@google.com/
>
>
> Mostafa Saleh (4):
> arm64: Introduce esr_is_ubsan_brk()
> ubsan: Remove regs from report_ubsan_failure()
> KVM: arm64: Introduce CONFIG_UBSAN_KVM_EL2
> KVM: arm64: Handle UBSAN faults
>
> arch/arm64/include/asm/esr.h | 5 +++++
> arch/arm64/kernel/traps.c | 4 ++--
> arch/arm64/kvm/handle_exit.c | 6 ++++++
> arch/arm64/kvm/hyp/nvhe/Makefile | 6 ++++++
> arch/x86/kernel/traps.c | 2 +-
> include/linux/ubsan.h | 6 +++---
> lib/Kconfig.ubsan | 9 +++++++++
> lib/ubsan.c | 8 +++++---
> scripts/Makefile.ubsan | 5 ++++-
> 9 files changed, 41 insertions(+), 10 deletions(-)
Nice! I assume this will go via the arm64 tree? I could carry it also,
if I get arm64 maintainer Acks...
-Kees
--
Kees Cook
^ permalink raw reply [flat|nested] 9+ messages in thread