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 <[email protected]> --- 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

