[PATCH v3 7/8] sframe: Introduce in-kernel SFRAME_VALIDATION.

Dylan Hatch
2026-04-06T18:50:33Z

Generalize the __safe* helpers to support a non-user-access code path.
Allow for kernel FDE read failures due to the presence of .rodata.text.
This section contains code that can't be executed by the kernel
direclty, and thus lies ouside the normal kernel-text bounds.

Signed-off-by: Dylan Hatch <dylanbhatch@google.com>
---
arch/Kconfig | 2 +-
kernel/unwind/sframe.c | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index c87e489fa978..6e9f21231b98 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -503,7 +503,7 @@ config HAVE_UNWIND_USER_SFRAME

config SFRAME_VALIDATION
bool "Enable .sframe section debugging"
- depends on HAVE_UNWIND_USER_SFRAME
+ depends on SFRAME_LOOKUP
depends on DYNAMIC_DEBUG
help
When adding an .sframe section for a task, validate the entire
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 180f64040846..7096e0a244b4 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -638,6 +638,9 @@ static int safe_read_fde(struct sframe_section *sec,
{
int ret;

+ if (sec->sec_type == SFRAME_KERNEL)
+ return __read_fde(sec, fde_num, fde);
+
if (!user_read_access_begin((void __user *)sec->sframe_start,
sec->sframe_end - sec->sframe_start))
return -EFAULT;
@@ -653,6 +656,9 @@ static int safe_read_fre(struct sframe_section *sec,
{
int ret;

+ if (sec->sec_type == SFRAME_KERNEL)
+ return __read_fre(sec, fde, fre_addr, fre);
+
if (!user_read_access_begin((void __user *)sec->sframe_start,
sec->sframe_end - sec->sframe_start))
return -EFAULT;
@@ -667,6 +673,9 @@ static int safe_read_fre_datawords(struct sframe_section *sec,
{
int ret;

+ if (sec->sec_type == SFRAME_KERNEL)
+ return __read_fre_datawords(sec, fde, fre);
+
if (!user_read_access_begin((void __user *)sec->sframe_start,
sec->sframe_end - sec->sframe_start))
return -EFAULT;
@@ -690,6 +699,13 @@ static int sframe_validate_section(struct sframe_section *sec)
int ret;

ret = safe_read_fde(sec, i, &fde);
+ /*
+ * Code in .rodata.text is not considered part of normal kernel
+ * text, but there is no easy way to prevent sframe data from
+ * being generated for it.
+ */
+ if (ret && sec->sec_type == SFRAME_KERNEL)
+ continue;
if (ret)
return ret;

@@ -1015,6 +1031,8 @@ void __init init_sframe_table(void)

if (WARN_ON(sframe_read_header(&kernel_sfsec)))
return;
+ if (WARN_ON(sframe_validate_section(&kernel_sfsec)))
+ return;

sframe_init = true;
}
@@ -1032,6 +1050,8 @@ void sframe_module_init(struct module *mod, void *sframe, size_t sframe_size,

if (WARN_ON(sframe_read_header(&sec)))
return;
+ if (WARN_ON(sframe_validate_section(&sec)))
+ return;

mod->arch.sframe_sec = sec;
mod->arch.sframe_init = true;
--
2.53.0.1213.gd9a14994de-goog