[PATCH v2 1/3] arm64: extable: Add fixup handling for uaccess CPY* instructions
Robin Murphy
robin.murphy at arm.com
Thu Mar 6 07:23:19 PST 2025
On 28/02/2025 5:00 pm, Kristina Martšenko wrote:
> A subsequent patch will use CPY* instructions to copy between user and
> kernel memory. Add a new exception fixup type to avoid fixing up faults
> on kernel memory accesses, in order to make it easier to debug kernel
> bugs and to keep the same behavior as with regular loads/stores.
Trusting my "the rest looks OK to me" from last time since I've already
paged the details back out again... :)
Reviewed-by: Robin Murphy <robin.murphy at arm.com>
> Signed-off-by: Kristina Martšenko <kristina.martsenko at arm.com>
> ---
> arch/arm64/include/asm/asm-extable.h | 10 +++++++++-
> arch/arm64/include/asm/extable.h | 2 +-
> arch/arm64/mm/extable.c | 25 ++++++++++++++++++++++++-
> arch/arm64/mm/fault.c | 2 +-
> 4 files changed, 35 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm64/include/asm/asm-extable.h b/arch/arm64/include/asm/asm-extable.h
> index b8a5861dc7b7..292f2687a12e 100644
> --- a/arch/arm64/include/asm/asm-extable.h
> +++ b/arch/arm64/include/asm/asm-extable.h
> @@ -9,7 +9,8 @@
> #define EX_TYPE_BPF 1
> #define EX_TYPE_UACCESS_ERR_ZERO 2
> #define EX_TYPE_KACCESS_ERR_ZERO 3
> -#define EX_TYPE_LOAD_UNALIGNED_ZEROPAD 4
> +#define EX_TYPE_UACCESS_CPY 4
> +#define EX_TYPE_LOAD_UNALIGNED_ZEROPAD 5
>
> /* Data fields for EX_TYPE_UACCESS_ERR_ZERO */
> #define EX_DATA_REG_ERR_SHIFT 0
> @@ -23,6 +24,9 @@
> #define EX_DATA_REG_ADDR_SHIFT 5
> #define EX_DATA_REG_ADDR GENMASK(9, 5)
>
> +/* Data fields for EX_TYPE_UACCESS_CPY */
> +#define EX_DATA_UACCESS_WRITE BIT(0)
> +
> #ifdef __ASSEMBLY__
>
> #define __ASM_EXTABLE_RAW(insn, fixup, type, data) \
> @@ -69,6 +73,10 @@
> .endif
> .endm
>
> + .macro _asm_extable_uaccess_cpy, insn, fixup, uaccess_is_write
> + __ASM_EXTABLE_RAW(\insn, \fixup, EX_TYPE_UACCESS_CPY, \uaccess_is_write)
> + .endm
> +
> #else /* __ASSEMBLY__ */
>
> #include <linux/stringify.h>
> diff --git a/arch/arm64/include/asm/extable.h b/arch/arm64/include/asm/extable.h
> index 72b0e71cc3de..5892b8977710 100644
> --- a/arch/arm64/include/asm/extable.h
> +++ b/arch/arm64/include/asm/extable.h
> @@ -45,5 +45,5 @@ bool ex_handler_bpf(const struct exception_table_entry *ex,
> }
> #endif /* !CONFIG_BPF_JIT */
>
> -bool fixup_exception(struct pt_regs *regs);
> +bool fixup_exception(struct pt_regs *regs, unsigned long esr);
> #endif
> diff --git a/arch/arm64/mm/extable.c b/arch/arm64/mm/extable.c
> index 228d681a8715..afb5241e4d91 100644
> --- a/arch/arm64/mm/extable.c
> +++ b/arch/arm64/mm/extable.c
> @@ -8,8 +8,18 @@
> #include <linux/uaccess.h>
>
> #include <asm/asm-extable.h>
> +#include <asm/esr.h>
> #include <asm/ptrace.h>
>
> +static bool cpy_faulted_on_uaccess(const struct exception_table_entry *ex,
> + unsigned long esr)
> +{
> + bool uaccess_is_write = FIELD_GET(EX_DATA_UACCESS_WRITE, ex->data);
> + bool fault_on_write = esr & ESR_ELx_WNR;
> +
> + return uaccess_is_write == fault_on_write;
> +}
> +
> static inline unsigned long
> get_ex_fixup(const struct exception_table_entry *ex)
> {
> @@ -29,6 +39,17 @@ static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
> return true;
> }
>
> +static bool ex_handler_uaccess_cpy(const struct exception_table_entry *ex,
> + struct pt_regs *regs, unsigned long esr)
> +{
> + /* Do not fix up faults on kernel memory accesses */
> + if (!cpy_faulted_on_uaccess(ex, esr))
> + return false;
> +
> + regs->pc = get_ex_fixup(ex);
> + return true;
> +}
> +
> static bool
> ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex,
> struct pt_regs *regs)
> @@ -56,7 +77,7 @@ ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex,
> return true;
> }
>
> -bool fixup_exception(struct pt_regs *regs)
> +bool fixup_exception(struct pt_regs *regs, unsigned long esr)
> {
> const struct exception_table_entry *ex;
>
> @@ -70,6 +91,8 @@ bool fixup_exception(struct pt_regs *regs)
> case EX_TYPE_UACCESS_ERR_ZERO:
> case EX_TYPE_KACCESS_ERR_ZERO:
> return ex_handler_uaccess_err_zero(ex, regs);
> + case EX_TYPE_UACCESS_CPY:
> + return ex_handler_uaccess_cpy(ex, regs, esr);
> case EX_TYPE_LOAD_UNALIGNED_ZEROPAD:
> return ex_handler_load_unaligned_zeropad(ex, regs);
> }
> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index ef63651099a9..da4854fc6150 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -375,7 +375,7 @@ static void __do_kernel_fault(unsigned long addr, unsigned long esr,
> * Are we prepared to handle this kernel fault?
> * We are almost certainly not prepared to handle instruction faults.
> */
> - if (!is_el1_instruction_abort(esr) && fixup_exception(regs))
> + if (!is_el1_instruction_abort(esr) && fixup_exception(regs, esr))
> return;
>
> if (WARN_RATELIMIT(is_spurious_el1_translation_fault(addr, esr, regs),
More information about the linux-arm-kernel
mailing list