Commit dceec3ff authored by Peter Collingbourne's avatar Peter Collingbourne Committed by Catalin Marinas

arm64: expose FAR_EL1 tag bits in siginfo

The kernel currently clears the tag bits (i.e. bits 56-63) in the fault
address exposed via siginfo.si_addr and sigcontext.fault_address. However,
the tag bits may be needed by tools in order to accurately diagnose
memory errors, such as HWASan [1] or future tools based on the Memory
Tagging Extension (MTE).

Expose these bits via the arch_untagged_si_addr mechanism, so that
they are only exposed to signal handlers with the SA_EXPOSE_TAGBITS
flag set.

[1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.htmlSigned-off-by: default avatarPeter Collingbourne <pcc@google.com>
Reviewed-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Link: https://linux-review.googlesource.com/id/Ia8876bad8c798e0a32df7c2ce1256c4771c81446
Link: https://lore.kernel.org/r/0010296597784267472fa13b39f8238d87a72cf8.1605904350.git.pcc@google.comSigned-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 6ac05e83
...@@ -53,12 +53,25 @@ visibility. ...@@ -53,12 +53,25 @@ visibility.
Preserving tags Preserving tags
--------------- ---------------
Non-zero tags are not preserved when delivering signals. This means that When delivering signals, non-zero tags are not preserved in
signal handlers in applications making use of tags cannot rely on the siginfo.si_addr unless the flag SA_EXPOSE_TAGBITS was set in
tag information for user virtual addresses being maintained for fields sigaction.sa_flags when the signal handler was installed. This means
inside siginfo_t. One exception to this rule is for signals raised in that signal handlers in applications making use of tags cannot rely
response to watchpoint debug exceptions, where the tag information will on the tag information for user virtual addresses being maintained
be preserved. in these fields unless the flag was set.
Due to architecture limitations, bits 63:60 of the fault address
are not preserved in response to synchronous tag check faults
(SEGV_MTESERR) even if SA_EXPOSE_TAGBITS was set. Applications should
treat the values of these bits as undefined in order to accommodate
future architecture revisions which may preserve the bits.
For signals raised in response to watchpoint debug exceptions, the
tag information will be preserved regardless of the SA_EXPOSE_TAGBITS
flag setting.
Non-zero tags are never preserved in sigcontext.fault_address
regardless of the SA_EXPOSE_TAGBITS flag setting.
The architecture prevents the use of a tagged PC, so the upper byte will The architecture prevents the use of a tagged PC, so the upper byte will
be set to a sign-extension of bit 55 on exception return. be set to a sign-extension of bit 55 on exception return.
......
...@@ -32,7 +32,7 @@ static inline u32 disr_to_esr(u64 disr) ...@@ -32,7 +32,7 @@ static inline u32 disr_to_esr(u64 disr)
} }
asmlinkage void enter_from_user_mode(void); asmlinkage void enter_from_user_mode(void);
void do_mem_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs); void do_mem_abort(unsigned long far, unsigned int esr, struct pt_regs *regs);
void do_undefinstr(struct pt_regs *regs); void do_undefinstr(struct pt_regs *regs);
void do_bti(struct pt_regs *regs); void do_bti(struct pt_regs *regs);
asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr); asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr);
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ARM64_ASM_SIGNAL_H
#define __ARM64_ASM_SIGNAL_H
#include <asm/memory.h>
#include <uapi/asm/signal.h>
#include <uapi/asm/siginfo.h>
static inline void __user *arch_untagged_si_addr(void __user *addr,
unsigned long sig,
unsigned long si_code)
{
/*
* For historical reasons, all bits of the fault address are exposed as
* address bits for watchpoint exceptions. New architectures should
* handle the tag bits consistently.
*/
if (sig == SIGTRAP && si_code == TRAP_BRKPT)
return addr;
return untagged_addr(addr);
}
#define arch_untagged_si_addr arch_untagged_si_addr
#endif
...@@ -22,7 +22,7 @@ void die(const char *msg, struct pt_regs *regs, int err); ...@@ -22,7 +22,7 @@ void die(const char *msg, struct pt_regs *regs, int err);
struct siginfo; struct siginfo;
void arm64_notify_die(const char *str, struct pt_regs *regs, void arm64_notify_die(const char *str, struct pt_regs *regs,
int signo, int sicode, void __user *addr, int signo, int sicode, unsigned long far,
int err); int err);
void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int, void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
......
...@@ -26,9 +26,9 @@ void register_undef_hook(struct undef_hook *hook); ...@@ -26,9 +26,9 @@ void register_undef_hook(struct undef_hook *hook);
void unregister_undef_hook(struct undef_hook *hook); void unregister_undef_hook(struct undef_hook *hook);
void force_signal_inject(int signal, int code, unsigned long address, unsigned int err); void force_signal_inject(int signal, int code, unsigned long address, unsigned int err);
void arm64_notify_segfault(unsigned long addr); void arm64_notify_segfault(unsigned long addr);
void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str); void arm64_force_sig_fault(int signo, int code, unsigned long far, const char *str);
void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, const char *str); void arm64_force_sig_mceerr(int code, unsigned long far, short lsb, const char *str);
void arm64_force_sig_ptrace_errno_trap(int errno, void __user *addr, const char *str); void arm64_force_sig_ptrace_errno_trap(int errno, unsigned long far, const char *str);
/* /*
* Move regs->pc to next instruction and do necessary setup before it * Move regs->pc to next instruction and do necessary setup before it
......
...@@ -234,9 +234,8 @@ static void send_user_sigtrap(int si_code) ...@@ -234,9 +234,8 @@ static void send_user_sigtrap(int si_code)
if (interrupts_enabled(regs)) if (interrupts_enabled(regs))
local_irq_enable(); local_irq_enable();
arm64_force_sig_fault(SIGTRAP, si_code, arm64_force_sig_fault(SIGTRAP, si_code, instruction_pointer(regs),
(void __user *)instruction_pointer(regs), "User debug trap");
"User debug trap");
} }
static int single_step_handler(unsigned long unused, unsigned int esr, static int single_step_handler(unsigned long unused, unsigned int esr,
......
...@@ -22,7 +22,6 @@ static void notrace el1_abort(struct pt_regs *regs, unsigned long esr) ...@@ -22,7 +22,6 @@ static void notrace el1_abort(struct pt_regs *regs, unsigned long esr)
unsigned long far = read_sysreg(far_el1); unsigned long far = read_sysreg(far_el1);
local_daif_inherit(regs); local_daif_inherit(regs);
far = untagged_addr(far);
do_mem_abort(far, esr, regs); do_mem_abort(far, esr, regs);
} }
NOKPROBE_SYMBOL(el1_abort); NOKPROBE_SYMBOL(el1_abort);
...@@ -114,7 +113,6 @@ static void notrace el0_da(struct pt_regs *regs, unsigned long esr) ...@@ -114,7 +113,6 @@ static void notrace el0_da(struct pt_regs *regs, unsigned long esr)
user_exit_irqoff(); user_exit_irqoff();
local_daif_restore(DAIF_PROCCTX); local_daif_restore(DAIF_PROCCTX);
far = untagged_addr(far);
do_mem_abort(far, esr, regs); do_mem_abort(far, esr, regs);
} }
NOKPROBE_SYMBOL(el0_da); NOKPROBE_SYMBOL(el0_da);
......
...@@ -192,14 +192,11 @@ static void ptrace_hbptriggered(struct perf_event *bp, ...@@ -192,14 +192,11 @@ static void ptrace_hbptriggered(struct perf_event *bp,
break; break;
} }
} }
arm64_force_sig_ptrace_errno_trap(si_errno, arm64_force_sig_ptrace_errno_trap(si_errno, bkpt->trigger,
(void __user *)bkpt->trigger,
desc); desc);
} }
#endif #endif
arm64_force_sig_fault(SIGTRAP, TRAP_HWBKPT, arm64_force_sig_fault(SIGTRAP, TRAP_HWBKPT, bkpt->trigger, desc);
(void __user *)(bkpt->trigger),
desc);
} }
/* /*
......
...@@ -68,7 +68,7 @@ do_compat_cache_op(unsigned long start, unsigned long end, int flags) ...@@ -68,7 +68,7 @@ do_compat_cache_op(unsigned long start, unsigned long end, int flags)
*/ */
long compat_arm_syscall(struct pt_regs *regs, int scno) long compat_arm_syscall(struct pt_regs *regs, int scno)
{ {
void __user *addr; unsigned long addr;
switch (scno) { switch (scno) {
/* /*
...@@ -111,8 +111,7 @@ long compat_arm_syscall(struct pt_regs *regs, int scno) ...@@ -111,8 +111,7 @@ long compat_arm_syscall(struct pt_regs *regs, int scno)
break; break;
} }
addr = (void __user *)instruction_pointer(regs) - addr = instruction_pointer(regs) - (compat_thumb_mode(regs) ? 2 : 4);
(compat_thumb_mode(regs) ? 2 : 4);
arm64_notify_die("Oops - bad compat syscall(2)", regs, arm64_notify_die("Oops - bad compat syscall(2)", regs,
SIGILL, ILL_ILLTRP, addr, scno); SIGILL, ILL_ILLTRP, addr, scno);
......
...@@ -170,32 +170,32 @@ static void arm64_show_signal(int signo, const char *str) ...@@ -170,32 +170,32 @@ static void arm64_show_signal(int signo, const char *str)
__show_regs(regs); __show_regs(regs);
} }
void arm64_force_sig_fault(int signo, int code, void __user *addr, void arm64_force_sig_fault(int signo, int code, unsigned long far,
const char *str) const char *str)
{ {
arm64_show_signal(signo, str); arm64_show_signal(signo, str);
if (signo == SIGKILL) if (signo == SIGKILL)
force_sig(SIGKILL); force_sig(SIGKILL);
else else
force_sig_fault(signo, code, addr); force_sig_fault(signo, code, (void __user *)far);
} }
void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, void arm64_force_sig_mceerr(int code, unsigned long far, short lsb,
const char *str) const char *str)
{ {
arm64_show_signal(SIGBUS, str); arm64_show_signal(SIGBUS, str);
force_sig_mceerr(code, addr, lsb); force_sig_mceerr(code, (void __user *)far, lsb);
} }
void arm64_force_sig_ptrace_errno_trap(int errno, void __user *addr, void arm64_force_sig_ptrace_errno_trap(int errno, unsigned long far,
const char *str) const char *str)
{ {
arm64_show_signal(SIGTRAP, str); arm64_show_signal(SIGTRAP, str);
force_sig_ptrace_errno_trap(errno, addr); force_sig_ptrace_errno_trap(errno, (void __user *)far);
} }
void arm64_notify_die(const char *str, struct pt_regs *regs, void arm64_notify_die(const char *str, struct pt_regs *regs,
int signo, int sicode, void __user *addr, int signo, int sicode, unsigned long far,
int err) int err)
{ {
if (user_mode(regs)) { if (user_mode(regs)) {
...@@ -203,7 +203,7 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, ...@@ -203,7 +203,7 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
current->thread.fault_address = 0; current->thread.fault_address = 0;
current->thread.fault_code = err; current->thread.fault_code = err;
arm64_force_sig_fault(signo, sicode, addr, str); arm64_force_sig_fault(signo, sicode, far, str);
} else { } else {
die(str, regs, err); die(str, regs, err);
} }
...@@ -374,7 +374,7 @@ void force_signal_inject(int signal, int code, unsigned long address, unsigned i ...@@ -374,7 +374,7 @@ void force_signal_inject(int signal, int code, unsigned long address, unsigned i
signal = SIGKILL; signal = SIGKILL;
} }
arm64_notify_die(desc, regs, signal, code, (void __user *)address, err); arm64_notify_die(desc, regs, signal, code, address, err);
} }
/* /*
...@@ -385,7 +385,7 @@ void arm64_notify_segfault(unsigned long addr) ...@@ -385,7 +385,7 @@ void arm64_notify_segfault(unsigned long addr)
int code; int code;
mmap_read_lock(current->mm); mmap_read_lock(current->mm);
if (find_vma(current->mm, addr) == NULL) if (find_vma(current->mm, untagged_addr(addr)) == NULL)
code = SEGV_MAPERR; code = SEGV_MAPERR;
else else
code = SEGV_ACCERR; code = SEGV_ACCERR;
...@@ -448,12 +448,13 @@ NOKPROBE_SYMBOL(do_ptrauth_fault); ...@@ -448,12 +448,13 @@ NOKPROBE_SYMBOL(do_ptrauth_fault);
static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs) static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
{ {
unsigned long address; unsigned long tagged_address, address;
int rt = ESR_ELx_SYS64_ISS_RT(esr); int rt = ESR_ELx_SYS64_ISS_RT(esr);
int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT; int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
int ret = 0; int ret = 0;
address = untagged_addr(pt_regs_read_reg(regs, rt)); tagged_address = pt_regs_read_reg(regs, rt);
address = untagged_addr(tagged_address);
switch (crm) { switch (crm) {
case ESR_ELx_SYS64_ISS_CRM_DC_CVAU: /* DC CVAU, gets promoted */ case ESR_ELx_SYS64_ISS_CRM_DC_CVAU: /* DC CVAU, gets promoted */
...@@ -480,7 +481,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs) ...@@ -480,7 +481,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
} }
if (ret) if (ret)
arm64_notify_segfault(address); arm64_notify_segfault(tagged_address);
else else
arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
} }
...@@ -772,7 +773,7 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr) ...@@ -772,7 +773,7 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
*/ */
void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr) void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
{ {
void __user *pc = (void __user *)instruction_pointer(regs); unsigned long pc = instruction_pointer(regs);
current->thread.fault_address = 0; current->thread.fault_address = 0;
current->thread.fault_code = esr; current->thread.fault_code = esr;
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#include <asm/traps.h> #include <asm/traps.h>
struct fault_info { struct fault_info {
int (*fn)(unsigned long addr, unsigned int esr, int (*fn)(unsigned long far, unsigned int esr,
struct pt_regs *regs); struct pt_regs *regs);
int sig; int sig;
int code; int code;
...@@ -385,8 +385,11 @@ static void set_thread_esr(unsigned long address, unsigned int esr) ...@@ -385,8 +385,11 @@ static void set_thread_esr(unsigned long address, unsigned int esr)
current->thread.fault_code = esr; current->thread.fault_code = esr;
} }
static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs) static void do_bad_area(unsigned long far, unsigned int esr,
struct pt_regs *regs)
{ {
unsigned long addr = untagged_addr(far);
/* /*
* If we are in kernel mode at this point, we have no context to * If we are in kernel mode at this point, we have no context to
* handle this fault with. * handle this fault with.
...@@ -395,8 +398,7 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re ...@@ -395,8 +398,7 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re
const struct fault_info *inf = esr_to_fault_info(esr); const struct fault_info *inf = esr_to_fault_info(esr);
set_thread_esr(addr, esr); set_thread_esr(addr, esr);
arm64_force_sig_fault(inf->sig, inf->code, (void __user *)addr, arm64_force_sig_fault(inf->sig, inf->code, far, inf->name);
inf->name);
} else { } else {
__do_kernel_fault(addr, esr, regs); __do_kernel_fault(addr, esr, regs);
} }
...@@ -448,7 +450,7 @@ static bool is_write_abort(unsigned int esr) ...@@ -448,7 +450,7 @@ static bool is_write_abort(unsigned int esr)
return (esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM); return (esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM);
} }
static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, static int __kprobes do_page_fault(unsigned long far, unsigned int esr,
struct pt_regs *regs) struct pt_regs *regs)
{ {
const struct fault_info *inf; const struct fault_info *inf;
...@@ -456,6 +458,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, ...@@ -456,6 +458,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
vm_fault_t fault; vm_fault_t fault;
unsigned long vm_flags = VM_ACCESS_FLAGS; unsigned long vm_flags = VM_ACCESS_FLAGS;
unsigned int mm_flags = FAULT_FLAG_DEFAULT; unsigned int mm_flags = FAULT_FLAG_DEFAULT;
unsigned long addr = untagged_addr(far);
if (kprobe_page_fault(regs, esr)) if (kprobe_page_fault(regs, esr))
return 0; return 0;
...@@ -567,8 +570,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, ...@@ -567,8 +570,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
* We had some memory, but were unable to successfully fix up * We had some memory, but were unable to successfully fix up
* this page fault. * this page fault.
*/ */
arm64_force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)addr, arm64_force_sig_fault(SIGBUS, BUS_ADRERR, far, inf->name);
inf->name);
} else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) { } else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) {
unsigned int lsb; unsigned int lsb;
...@@ -576,8 +578,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, ...@@ -576,8 +578,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
if (fault & VM_FAULT_HWPOISON_LARGE) if (fault & VM_FAULT_HWPOISON_LARGE)
lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
arm64_force_sig_mceerr(BUS_MCEERR_AR, (void __user *)addr, lsb, arm64_force_sig_mceerr(BUS_MCEERR_AR, far, lsb, inf->name);
inf->name);
} else { } else {
/* /*
* Something tried to access memory that isn't in our memory * Something tried to access memory that isn't in our memory
...@@ -585,8 +586,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, ...@@ -585,8 +586,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
*/ */
arm64_force_sig_fault(SIGSEGV, arm64_force_sig_fault(SIGSEGV,
fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR, fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR,
(void __user *)addr, far, inf->name);
inf->name);
} }
return 0; return 0;
...@@ -596,33 +596,35 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, ...@@ -596,33 +596,35 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
return 0; return 0;
} }
static int __kprobes do_translation_fault(unsigned long addr, static int __kprobes do_translation_fault(unsigned long far,
unsigned int esr, unsigned int esr,
struct pt_regs *regs) struct pt_regs *regs)
{ {
unsigned long addr = untagged_addr(far);
if (is_ttbr0_addr(addr)) if (is_ttbr0_addr(addr))
return do_page_fault(addr, esr, regs); return do_page_fault(far, esr, regs);
do_bad_area(addr, esr, regs); do_bad_area(far, esr, regs);
return 0; return 0;
} }
static int do_alignment_fault(unsigned long addr, unsigned int esr, static int do_alignment_fault(unsigned long far, unsigned int esr,
struct pt_regs *regs) struct pt_regs *regs)
{ {
do_bad_area(addr, esr, regs); do_bad_area(far, esr, regs);
return 0; return 0;
} }
static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs) static int do_bad(unsigned long far, unsigned int esr, struct pt_regs *regs)
{ {
return 1; /* "fault" */ return 1; /* "fault" */
} }
static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) static int do_sea(unsigned long far, unsigned int esr, struct pt_regs *regs)
{ {
const struct fault_info *inf; const struct fault_info *inf;
void __user *siaddr; unsigned long siaddr;
inf = esr_to_fault_info(esr); inf = esr_to_fault_info(esr);
...@@ -634,19 +636,30 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) ...@@ -634,19 +636,30 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
return 0; return 0;
} }
if (esr & ESR_ELx_FnV) if (esr & ESR_ELx_FnV) {
siaddr = NULL; siaddr = 0;
else } else {
siaddr = (void __user *)addr; /*
* The architecture specifies that the tag bits of FAR_EL1 are
* UNKNOWN for synchronous external aborts. Mask them out now
* so that userspace doesn't see them.
*/
siaddr = untagged_addr(far);
}
arm64_notify_die(inf->name, regs, inf->sig, inf->code, siaddr, esr); arm64_notify_die(inf->name, regs, inf->sig, inf->code, siaddr, esr);
return 0; return 0;
} }
static int do_tag_check_fault(unsigned long addr, unsigned int esr, static int do_tag_check_fault(unsigned long far, unsigned int esr,
struct pt_regs *regs) struct pt_regs *regs)
{ {
do_bad_area(addr, esr, regs); /*
* The architecture specifies that bits 63:60 of FAR_EL1 are UNKNOWN for tag
* check faults. Mask them out now so that userspace doesn't see them.
*/
far &= (1UL << 60) - 1;
do_bad_area(far, esr, regs);
return 0; return 0;
} }
...@@ -717,11 +730,12 @@ static const struct fault_info fault_info[] = { ...@@ -717,11 +730,12 @@ static const struct fault_info fault_info[] = {
{ do_bad, SIGKILL, SI_KERNEL, "unknown 63" }, { do_bad, SIGKILL, SI_KERNEL, "unknown 63" },
}; };
void do_mem_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs) void do_mem_abort(unsigned long far, unsigned int esr, struct pt_regs *regs)
{ {
const struct fault_info *inf = esr_to_fault_info(esr); const struct fault_info *inf = esr_to_fault_info(esr);
unsigned long addr = untagged_addr(far);
if (!inf->fn(addr, esr, regs)) if (!inf->fn(far, esr, regs))
return; return;
if (!user_mode(regs)) { if (!user_mode(regs)) {
...@@ -730,8 +744,12 @@ void do_mem_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs) ...@@ -730,8 +744,12 @@ void do_mem_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs)
show_pte(addr); show_pte(addr);
} }
arm64_notify_die(inf->name, regs, /*
inf->sig, inf->code, (void __user *)addr, esr); * At this point we have an unrecognized fault type whose tag bits may
* have been defined as UNKNOWN. Therefore we only expose the untagged
* address to the signal handler.
*/
arm64_notify_die(inf->name, regs, inf->sig, inf->code, addr, esr);
} }
NOKPROBE_SYMBOL(do_mem_abort); NOKPROBE_SYMBOL(do_mem_abort);
...@@ -744,8 +762,8 @@ NOKPROBE_SYMBOL(do_el0_irq_bp_hardening); ...@@ -744,8 +762,8 @@ NOKPROBE_SYMBOL(do_el0_irq_bp_hardening);
void do_sp_pc_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs) void do_sp_pc_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs)
{ {
arm64_notify_die("SP/PC alignment exception", regs, arm64_notify_die("SP/PC alignment exception", regs, SIGBUS, BUS_ADRALN,
SIGBUS, BUS_ADRALN, (void __user *)addr, esr); addr, esr);
} }
NOKPROBE_SYMBOL(do_sp_pc_abort); NOKPROBE_SYMBOL(do_sp_pc_abort);
...@@ -871,8 +889,7 @@ void do_debug_exception(unsigned long addr_if_watchpoint, unsigned int esr, ...@@ -871,8 +889,7 @@ void do_debug_exception(unsigned long addr_if_watchpoint, unsigned int esr,
arm64_apply_bp_hardening(); arm64_apply_bp_hardening();
if (inf->fn(addr_if_watchpoint, esr, regs)) { if (inf->fn(addr_if_watchpoint, esr, regs)) {
arm64_notify_die(inf->name, regs, arm64_notify_die(inf->name, regs, inf->sig, inf->code, pc, esr);
inf->sig, inf->code, (void __user *)pc, esr);
} }
debug_exception_exit(regs); debug_exception_exit(regs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment