Commit ba9f6f89 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'siginfo-linus' of...

Merge branch 'siginfo-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull siginfo updates from Eric Biederman:
 "I have been slowly sorting out siginfo and this is the culmination of
  that work.

  The primary result is in several ways the signal infrastructure has
  been made less error prone. The code has been updated so that manually
  specifying SEND_SIG_FORCED is never necessary. The conversion to the
  new siginfo sending functions is now complete, which makes it
  difficult to send a signal without filling in the proper siginfo
  fields.

  At the tail end of the patchset comes the optimization of decreasing
  the size of struct siginfo in the kernel from 128 bytes to about 48
  bytes on 64bit. The fundamental observation that enables this is by
  definition none of the known ways to use struct siginfo uses the extra
  bytes.

  This comes at the cost of a small user space observable difference.
  For the rare case of siginfo being injected into the kernel only what
  can be copied into kernel_siginfo is delivered to the destination, the
  rest of the bytes are set to 0. For cases where the signal and the
  si_code are known this is safe, because we know those bytes are not
  used. For cases where the signal and si_code combination is unknown
  the bits that won't fit into struct kernel_siginfo are tested to
  verify they are zero, and the send fails if they are not.

  I made an extensive search through userspace code and I could not find
  anything that would break because of the above change. If it turns out
  I did break something it will take just the revert of a single change
  to restore kernel_siginfo to the same size as userspace siginfo.

  Testing did reveal dependencies on preferring the signo passed to
  sigqueueinfo over si->signo, so bit the bullet and added the
  complexity necessary to handle that case.

  Testing also revealed bad things can happen if a negative signal
  number is passed into the system calls. Something no sane application
  will do but something a malicious program or a fuzzer might do. So I
  have fixed the code that performs the bounds checks to ensure negative
  signal numbers are handled"

* 'siginfo-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (80 commits)
  signal: Guard against negative signal numbers in copy_siginfo_from_user32
  signal: Guard against negative signal numbers in copy_siginfo_from_user
  signal: In sigqueueinfo prefer sig not si_signo
  signal: Use a smaller struct siginfo in the kernel
  signal: Distinguish between kernel_siginfo and siginfo
  signal: Introduce copy_siginfo_from_user and use it's return value
  signal: Remove the need for __ARCH_SI_PREABLE_SIZE and SI_PAD_SIZE
  signal: Fail sigqueueinfo if si_signo != sig
  signal/sparc: Move EMT_TAGOVF into the generic siginfo.h
  signal/unicore32: Use force_sig_fault where appropriate
  signal/unicore32: Generate siginfo in ucs32_notify_die
  signal/unicore32: Use send_sig_fault where appropriate
  signal/arc: Use force_sig_fault where appropriate
  signal/arc: Push siginfo generation into unhandled_exception
  signal/ia64: Use force_sig_fault where appropriate
  signal/ia64: Use the force_sig(SIGSEGV,...) in ia64_rt_sigreturn
  signal/ia64: Use the generic force_sigsegv in setup_frame
  signal/arm/kvm: Use send_sig_mceerr
  signal/arm: Use send_sig_fault where appropriate
  signal/arm: Use force_sig_fault where appropriate
  ...
parents a978a5b8 a3670058
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#ifndef _ALPHA_SIGINFO_H #ifndef _ALPHA_SIGINFO_H
#define _ALPHA_SIGINFO_H #define _ALPHA_SIGINFO_H
#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
#define __ARCH_SI_TRAPNO #define __ARCH_SI_TRAPNO
#include <asm-generic/siginfo.h> #include <asm-generic/siginfo.h>
......
...@@ -42,21 +42,22 @@ void die(const char *str, struct pt_regs *regs, unsigned long address) ...@@ -42,21 +42,22 @@ void die(const char *str, struct pt_regs *regs, unsigned long address)
* -for kernel, chk if due to copy_(to|from)_user, otherwise die() * -for kernel, chk if due to copy_(to|from)_user, otherwise die()
*/ */
static noinline int static noinline int
unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info) unhandled_exception(const char *str, struct pt_regs *regs,
int signo, int si_code, void __user *addr)
{ {
if (user_mode(regs)) { if (user_mode(regs)) {
struct task_struct *tsk = current; struct task_struct *tsk = current;
tsk->thread.fault_address = (__force unsigned int)info->si_addr; tsk->thread.fault_address = (__force unsigned int)addr;
force_sig_info(info->si_signo, info, tsk); force_sig_fault(signo, si_code, addr, tsk);
} else { } else {
/* If not due to copy_(to|from)_user, we are doomed */ /* If not due to copy_(to|from)_user, we are doomed */
if (fixup_exception(regs)) if (fixup_exception(regs))
return 0; return 0;
die(str, regs, (unsigned long)info->si_addr); die(str, regs, (unsigned long)addr);
} }
return 1; return 1;
...@@ -64,16 +65,9 @@ unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info) ...@@ -64,16 +65,9 @@ unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info)
#define DO_ERROR_INFO(signr, str, name, sicode) \ #define DO_ERROR_INFO(signr, str, name, sicode) \
int name(unsigned long address, struct pt_regs *regs) \ int name(unsigned long address, struct pt_regs *regs) \
{ \ { \
siginfo_t info; \ return unhandled_exception(str, regs, signr, sicode, \
\ (void __user *)address); \
clear_siginfo(&info); \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
info.si_addr = (void __user *)address; \
\
return unhandled_exception(str, regs, &info);\
} }
/* /*
......
...@@ -66,14 +66,12 @@ void do_page_fault(unsigned long address, struct pt_regs *regs) ...@@ -66,14 +66,12 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
struct vm_area_struct *vma = NULL; struct vm_area_struct *vma = NULL;
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm; struct mm_struct *mm = tsk->mm;
siginfo_t info; int si_code;
int ret; int ret;
vm_fault_t fault; vm_fault_t fault;
int write = regs->ecr_cause & ECR_C_PROTV_STORE; /* ST/EX */ int write = regs->ecr_cause & ECR_C_PROTV_STORE; /* ST/EX */
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
clear_siginfo(&info);
/* /*
* We fault-in kernel-space virtual memory on-demand. The * We fault-in kernel-space virtual memory on-demand. The
* 'reference' page table is init_mm.pgd. * 'reference' page table is init_mm.pgd.
...@@ -91,7 +89,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs) ...@@ -91,7 +89,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
return; return;
} }
info.si_code = SEGV_MAPERR; si_code = SEGV_MAPERR;
/* /*
* If we're in an interrupt or have no user * If we're in an interrupt or have no user
...@@ -119,7 +117,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs) ...@@ -119,7 +117,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
* we can handle it.. * we can handle it..
*/ */
good_area: good_area:
info.si_code = SEGV_ACCERR; si_code = SEGV_ACCERR;
/* Handle protection violation, execute on heap or stack */ /* Handle protection violation, execute on heap or stack */
...@@ -199,11 +197,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs) ...@@ -199,11 +197,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
/* User mode accesses just cause a SIGSEGV */ /* User mode accesses just cause a SIGSEGV */
if (user_mode(regs)) { if (user_mode(regs)) {
tsk->thread.fault_address = address; tsk->thread.fault_address = address;
info.si_signo = SIGSEGV; force_sig_fault(SIGSEGV, si_code, (void __user *)address, tsk);
info.si_errno = 0;
/* info.si_code has been set above */
info.si_addr = (void __user *)address;
force_sig_info(SIGSEGV, &info, tsk);
return; return;
} }
...@@ -238,9 +232,5 @@ void do_page_fault(unsigned long address, struct pt_regs *regs) ...@@ -238,9 +232,5 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
goto no_context; goto no_context;
tsk->thread.fault_address = address; tsk->thread.fault_address = address;
info.si_signo = SIGBUS; force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, tsk);
info.si_errno = 0;
info.si_code = BUS_ADRERR;
info.si_addr = (void __user *)address;
force_sig_info(SIGBUS, &info, tsk);
} }
...@@ -62,8 +62,8 @@ do { \ ...@@ -62,8 +62,8 @@ do { \
struct pt_regs; struct pt_regs;
void die(const char *msg, struct pt_regs *regs, int err); void die(const char *msg, struct pt_regs *regs, int err);
struct siginfo; void arm_notify_die(const char *str, struct pt_regs *regs,
void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, int signo, int si_code, void __user *addr,
unsigned long err, unsigned long trap); unsigned long err, unsigned long trap);
#ifdef CONFIG_ARM_LPAE #ifdef CONFIG_ARM_LPAE
......
...@@ -203,15 +203,8 @@ void ptrace_disable(struct task_struct *child) ...@@ -203,15 +203,8 @@ void ptrace_disable(struct task_struct *child)
*/ */
void ptrace_break(struct task_struct *tsk, struct pt_regs *regs) void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
{ {
siginfo_t info; force_sig_fault(SIGTRAP, TRAP_BRKPT,
(void __user *)instruction_pointer(regs), tsk);
clear_siginfo(&info);
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
info.si_addr = (void __user *)instruction_pointer(regs);
force_sig_info(SIGTRAP, &info, tsk);
} }
static int break_trap(struct pt_regs *regs, unsigned int instr) static int break_trap(struct pt_regs *regs, unsigned int instr)
......
...@@ -98,22 +98,20 @@ static int proc_status_show(struct seq_file *m, void *v) ...@@ -98,22 +98,20 @@ static int proc_status_show(struct seq_file *m, void *v)
*/ */
static void set_segfault(struct pt_regs *regs, unsigned long addr) static void set_segfault(struct pt_regs *regs, unsigned long addr)
{ {
siginfo_t info; int si_code;
clear_siginfo(&info);
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
if (find_vma(current->mm, addr) == NULL) if (find_vma(current->mm, addr) == NULL)
info.si_code = SEGV_MAPERR; si_code = SEGV_MAPERR;
else else
info.si_code = SEGV_ACCERR; si_code = SEGV_ACCERR;
up_read(&current->mm->mmap_sem); up_read(&current->mm->mmap_sem);
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_addr = (void *) instruction_pointer(regs);
pr_debug("SWP{B} emulation: access caused memory abort!\n"); pr_debug("SWP{B} emulation: access caused memory abort!\n");
arm_notify_die("Illegal memory access", regs, &info, 0, 0); arm_notify_die("Illegal memory access", regs,
SIGSEGV, si_code,
(void __user *)instruction_pointer(regs),
0, 0);
abtcounter++; abtcounter++;
} }
......
...@@ -365,13 +365,14 @@ void die(const char *str, struct pt_regs *regs, int err) ...@@ -365,13 +365,14 @@ void die(const char *str, struct pt_regs *regs, int err)
} }
void arm_notify_die(const char *str, struct pt_regs *regs, void arm_notify_die(const char *str, struct pt_regs *regs,
struct siginfo *info, unsigned long err, unsigned long trap) int signo, int si_code, void __user *addr,
unsigned long err, unsigned long trap)
{ {
if (user_mode(regs)) { if (user_mode(regs)) {
current->thread.error_code = err; current->thread.error_code = err;
current->thread.trap_no = trap; current->thread.trap_no = trap;
force_sig_info(info->si_signo, info, current); force_sig_fault(signo, si_code, addr, current);
} else { } else {
die(str, regs, err); die(str, regs, err);
} }
...@@ -438,10 +439,8 @@ int call_undef_hook(struct pt_regs *regs, unsigned int instr) ...@@ -438,10 +439,8 @@ int call_undef_hook(struct pt_regs *regs, unsigned int instr)
asmlinkage void do_undefinstr(struct pt_regs *regs) asmlinkage void do_undefinstr(struct pt_regs *regs)
{ {
unsigned int instr; unsigned int instr;
siginfo_t info;
void __user *pc; void __user *pc;
clear_siginfo(&info);
pc = (void __user *)instruction_pointer(regs); pc = (void __user *)instruction_pointer(regs);
if (processor_mode(regs) == SVC_MODE) { if (processor_mode(regs) == SVC_MODE) {
...@@ -485,13 +484,8 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) ...@@ -485,13 +484,8 @@ asmlinkage void do_undefinstr(struct pt_regs *regs)
dump_instr(KERN_INFO, regs); dump_instr(KERN_INFO, regs);
} }
#endif #endif
arm_notify_die("Oops - undefined instruction", regs,
info.si_signo = SIGILL; SIGILL, ILL_ILLOPC, pc, 0, 6);
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = pc;
arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
} }
NOKPROBE_SYMBOL(do_undefinstr) NOKPROBE_SYMBOL(do_undefinstr)
...@@ -539,9 +533,6 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason) ...@@ -539,9 +533,6 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason)
static int bad_syscall(int n, struct pt_regs *regs) static int bad_syscall(int n, struct pt_regs *regs)
{ {
siginfo_t info;
clear_siginfo(&info);
if ((current->personality & PER_MASK) != PER_LINUX) { if ((current->personality & PER_MASK) != PER_LINUX) {
send_sig(SIGSEGV, current, 1); send_sig(SIGSEGV, current, 1);
return regs->ARM_r0; return regs->ARM_r0;
...@@ -555,13 +546,10 @@ static int bad_syscall(int n, struct pt_regs *regs) ...@@ -555,13 +546,10 @@ static int bad_syscall(int n, struct pt_regs *regs)
} }
#endif #endif
info.si_signo = SIGILL; arm_notify_die("Oops - bad syscall", regs, SIGILL, ILL_ILLTRP,
info.si_errno = 0; (void __user *)instruction_pointer(regs) -
info.si_code = ILL_ILLTRP; (thumb_mode(regs) ? 2 : 4),
info.si_addr = (void __user *)instruction_pointer(regs) - n, 0);
(thumb_mode(regs) ? 2 : 4);
arm_notify_die("Oops - bad syscall", regs, &info, n, 0);
return regs->ARM_r0; return regs->ARM_r0;
} }
...@@ -607,20 +595,13 @@ do_cache_op(unsigned long start, unsigned long end, int flags) ...@@ -607,20 +595,13 @@ do_cache_op(unsigned long start, unsigned long end, int flags)
#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE) #define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
asmlinkage int arm_syscall(int no, struct pt_regs *regs) asmlinkage int arm_syscall(int no, struct pt_regs *regs)
{ {
siginfo_t info;
clear_siginfo(&info);
if ((no >> 16) != (__ARM_NR_BASE>> 16)) if ((no >> 16) != (__ARM_NR_BASE>> 16))
return bad_syscall(no, regs); return bad_syscall(no, regs);
switch (no & 0xffff) { switch (no & 0xffff) {
case 0: /* branch through 0 */ case 0: /* branch through 0 */
info.si_signo = SIGSEGV; arm_notify_die("branch through zero", regs,
info.si_errno = 0; SIGSEGV, SEGV_MAPERR, NULL, 0, 0);
info.si_code = SEGV_MAPERR;
info.si_addr = NULL;
arm_notify_die("branch through zero", regs, &info, 0, 0);
return 0; return 0;
case NR(breakpoint): /* SWI BREAK_POINT */ case NR(breakpoint): /* SWI BREAK_POINT */
...@@ -688,13 +669,10 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) ...@@ -688,13 +669,10 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
} }
} }
#endif #endif
info.si_signo = SIGILL; arm_notify_die("Oops - bad syscall(2)", regs, SIGILL, ILL_ILLTRP,
info.si_errno = 0; (void __user *)instruction_pointer(regs) -
info.si_code = ILL_ILLTRP; (thumb_mode(regs) ? 2 : 4),
info.si_addr = (void __user *)instruction_pointer(regs) - no, 0);
(thumb_mode(regs) ? 2 : 4);
arm_notify_die("Oops - bad syscall(2)", regs, &info, no, 0);
return 0; return 0;
} }
...@@ -744,9 +722,6 @@ asmlinkage void ...@@ -744,9 +722,6 @@ asmlinkage void
baddataabort(int code, unsigned long instr, struct pt_regs *regs) baddataabort(int code, unsigned long instr, struct pt_regs *regs)
{ {
unsigned long addr = instruction_pointer(regs); unsigned long addr = instruction_pointer(regs);
siginfo_t info;
clear_siginfo(&info);
#ifdef CONFIG_DEBUG_USER #ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_BADABORT) { if (user_debug & UDBG_BADABORT) {
...@@ -757,12 +732,8 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) ...@@ -757,12 +732,8 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
} }
#endif #endif
info.si_signo = SIGILL; arm_notify_die("unknown data abort code", regs,
info.si_errno = 0; SIGILL, ILL_ILLOPC, (void __user *)addr, instr, 0);
info.si_code = ILL_ILLOPC;
info.si_addr = (void __user *)addr;
arm_notify_die("unknown data abort code", regs, &info, instr, 0);
} }
void __readwrite_bug(const char *fn) void __readwrite_bug(const char *fn)
......
...@@ -948,15 +948,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) ...@@ -948,15 +948,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
goto fixup; goto fixup;
if (ai_usermode & UM_SIGNAL) { if (ai_usermode & UM_SIGNAL) {
siginfo_t si; force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr, current);
clear_siginfo(&si);
si.si_signo = SIGBUS;
si.si_errno = 0;
si.si_code = BUS_ADRALN;
si.si_addr = (void __user *)addr;
force_sig_info(si.si_signo, &si, current);
} else { } else {
/* /*
* We're about to disable the alignment trap and return to * We're about to disable the alignment trap and return to
......
...@@ -161,13 +161,9 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, ...@@ -161,13 +161,9 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
unsigned int fsr, unsigned int sig, int code, unsigned int fsr, unsigned int sig, int code,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct siginfo si;
if (addr > TASK_SIZE) if (addr > TASK_SIZE)
harden_branch_predictor(); harden_branch_predictor();
clear_siginfo(&si);
#ifdef CONFIG_DEBUG_USER #ifdef CONFIG_DEBUG_USER
if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) || if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
((user_debug & UDBG_BUS) && (sig == SIGBUS))) { ((user_debug & UDBG_BUS) && (sig == SIGBUS))) {
...@@ -181,11 +177,7 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, ...@@ -181,11 +177,7 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
tsk->thread.address = addr; tsk->thread.address = addr;
tsk->thread.error_code = fsr; tsk->thread.error_code = fsr;
tsk->thread.trap_no = 14; tsk->thread.trap_no = 14;
si.si_signo = sig; force_sig_fault(sig, code, (void __user *)addr, tsk);
si.si_errno = 0;
si.si_code = code;
si.si_addr = (void __user *)addr;
force_sig_info(sig, &si, tsk);
} }
void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
...@@ -554,7 +546,6 @@ asmlinkage void ...@@ -554,7 +546,6 @@ asmlinkage void
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{ {
const struct fsr_info *inf = fsr_info + fsr_fs(fsr); const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
struct siginfo info;
if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
return; return;
...@@ -563,12 +554,8 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) ...@@ -563,12 +554,8 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
inf->name, fsr, addr); inf->name, fsr, addr);
show_pte(current->mm, addr); show_pte(current->mm, addr);
clear_siginfo(&info); arm_notify_die("", regs, inf->sig, inf->code, (void __user *)addr,
info.si_signo = inf->sig; fsr, 0);
info.si_errno = 0;
info.si_code = inf->code;
info.si_addr = (void __user *)addr;
arm_notify_die("", regs, &info, fsr, 0);
} }
void __init void __init
...@@ -588,7 +575,6 @@ asmlinkage void ...@@ -588,7 +575,6 @@ asmlinkage void
do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
{ {
const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr); const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
struct siginfo info;
if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
return; return;
...@@ -596,12 +582,8 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) ...@@ -596,12 +582,8 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n", pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
inf->name, ifsr, addr); inf->name, ifsr, addr);
clear_siginfo(&info); arm_notify_die("", regs, inf->sig, inf->code, (void __user *)addr,
info.si_signo = inf->sig; ifsr, 0);
info.si_errno = 0;
info.si_code = inf->code;
info.si_addr = (void __user *)addr;
arm_notify_die("", regs, &info, ifsr, 0);
} }
/* /*
......
...@@ -216,13 +216,6 @@ static struct notifier_block vfp_notifier_block = { ...@@ -216,13 +216,6 @@ static struct notifier_block vfp_notifier_block = {
*/ */
static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs) static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
{ {
siginfo_t info;
clear_siginfo(&info);
info.si_signo = SIGFPE;
info.si_code = sicode;
info.si_addr = (void __user *)(instruction_pointer(regs) - 4);
/* /*
* This is the same as NWFPE, because it's not clear what * This is the same as NWFPE, because it's not clear what
* this is used for * this is used for
...@@ -230,7 +223,9 @@ static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs) ...@@ -230,7 +223,9 @@ static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
current->thread.error_code = 0; current->thread.error_code = 0;
current->thread.trap_no = 6; current->thread.trap_no = 6;
send_sig_info(SIGFPE, &info, current); send_sig_fault(SIGFPE, sicode,
(void __user *)(instruction_pointer(regs) - 4),
current);
} }
static void vfp_panic(char *reason, u32 inst) static void vfp_panic(char *reason, u32 inst)
......
...@@ -33,7 +33,8 @@ void die(const char *msg, struct pt_regs *regs, int err); ...@@ -33,7 +33,8 @@ 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,
struct siginfo *info, int err); int signo, int sicode, void __user *addr,
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,
struct pt_regs *), struct pt_regs *),
......
...@@ -37,8 +37,9 @@ void register_undef_hook(struct undef_hook *hook); ...@@ -37,8 +37,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); void force_signal_inject(int signal, int code, unsigned long address);
void arm64_notify_segfault(unsigned long addr); void arm64_notify_segfault(unsigned long addr);
void arm64_force_sig_info(struct siginfo *info, const char *str, void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str);
struct task_struct *tsk); void arm64_force_sig_mceerr(int code, void __user *addr, short lsb, const char *str);
void arm64_force_sig_ptrace_errno_trap(int errno, void __user *addr, 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
......
...@@ -19,3 +19,4 @@ generic-y += swab.h ...@@ -19,3 +19,4 @@ generic-y += swab.h
generic-y += termbits.h generic-y += termbits.h
generic-y += termios.h generic-y += termios.h
generic-y += types.h generic-y += types.h
generic-y += siginfo.h
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (C) 2012 ARM Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ASM_SIGINFO_H
#define __ASM_SIGINFO_H
#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
#include <asm-generic/siginfo.h>
#endif
...@@ -210,13 +210,6 @@ NOKPROBE_SYMBOL(call_step_hook); ...@@ -210,13 +210,6 @@ NOKPROBE_SYMBOL(call_step_hook);
static void send_user_sigtrap(int si_code) static void send_user_sigtrap(int si_code)
{ {
struct pt_regs *regs = current_pt_regs(); struct pt_regs *regs = current_pt_regs();
siginfo_t info;
clear_siginfo(&info);
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = si_code;
info.si_addr = (void __user *)instruction_pointer(regs);
if (WARN_ON(!user_mode(regs))) if (WARN_ON(!user_mode(regs)))
return; return;
...@@ -224,7 +217,9 @@ static void send_user_sigtrap(int si_code) ...@@ -224,7 +217,9 @@ 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_info(&info, "User debug trap", current); arm64_force_sig_fault(SIGTRAP, si_code,
(void __user *)instruction_pointer(regs),
"User debug trap");
} }
static int single_step_handler(unsigned long addr, unsigned int esr, static int single_step_handler(unsigned long addr, unsigned int esr,
......
...@@ -842,7 +842,6 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) ...@@ -842,7 +842,6 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
*/ */
asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
{ {