summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/alpha/include/uapi/asm/siginfo.h1
-rw-r--r--arch/arc/kernel/traps.c22
-rw-r--r--arch/arc/mm/fault.c20
-rw-r--r--arch/arm/include/asm/bug.h4
-rw-r--r--arch/arm/kernel/ptrace.c11
-rw-r--r--arch/arm/kernel/swp_emulate.c16
-rw-r--r--arch/arm/kernel/traps.c63
-rw-r--r--arch/arm/mm/alignment.c10
-rw-r--r--arch/arm/mm/fault.c28
-rw-r--r--arch/arm/vfp/vfpmodule.c11
-rw-r--r--arch/arm64/include/asm/system_misc.h3
-rw-r--r--arch/arm64/include/asm/traps.h5
-rw-r--r--arch/arm64/include/uapi/asm/Kbuild1
-rw-r--r--arch/arm64/include/uapi/asm/siginfo.h24
-rw-r--r--arch/arm64/kernel/debug-monitors.c11
-rw-r--r--arch/arm64/kernel/fpsimd.c10
-rw-r--r--arch/arm64/kernel/ptrace.c16
-rw-r--r--arch/arm64/kernel/sys_compat.c13
-rw-r--r--arch/arm64/kernel/traps.c67
-rw-r--r--arch/arm64/mm/fault.c94
-rw-r--r--arch/ia64/include/uapi/asm/siginfo.h2
-rw-r--r--arch/ia64/kernel/brl_emu.c31
-rw-r--r--arch/ia64/kernel/signal.c60
-rw-r--r--arch/ia64/kernel/traps.c144
-rw-r--r--arch/ia64/kernel/unaligned.c12
-rw-r--r--arch/ia64/mm/fault.c12
-rw-r--r--arch/mips/include/uapi/asm/siginfo.h11
-rw-r--r--arch/parisc/include/uapi/asm/Kbuild1
-rw-r--r--arch/parisc/include/uapi/asm/siginfo.h11
-rw-r--r--arch/powerpc/include/asm/bug.h2
-rw-r--r--arch/powerpc/include/asm/ptrace.h2
-rw-r--r--arch/powerpc/include/uapi/asm/Kbuild1
-rw-r--r--arch/powerpc/include/uapi/asm/siginfo.h18
-rw-r--r--arch/powerpc/kernel/process.c9
-rw-r--r--arch/powerpc/kernel/traps.c34
-rw-r--r--arch/powerpc/mm/fault.c55
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/fault.c26
-rw-r--r--arch/riscv/include/uapi/asm/Kbuild1
-rw-r--r--arch/riscv/include/uapi/asm/siginfo.h24
-rw-r--r--arch/s390/include/uapi/asm/Kbuild1
-rw-r--r--arch/s390/include/uapi/asm/siginfo.h17
-rw-r--r--arch/sparc/include/uapi/asm/siginfo.h7
-rw-r--r--arch/unicore32/include/asm/bug.h3
-rw-r--r--arch/unicore32/kernel/fpu-ucf64.c12
-rw-r--r--arch/unicore32/kernel/traps.c5
-rw-r--r--arch/unicore32/mm/fault.c27
-rw-r--r--arch/x86/entry/vsyscall/vsyscall_64.c9
-rw-r--r--arch/x86/include/asm/compat.h2
-rw-r--r--arch/x86/include/asm/mpx.h12
-rw-r--r--arch/x86/include/asm/ptrace.h2
-rw-r--r--arch/x86/include/asm/trace/mpx.h4
-rw-r--r--arch/x86/include/uapi/asm/siginfo.h2
-rw-r--r--arch/x86/kernel/ptrace.c29
-rw-r--r--arch/x86/kernel/traps.c176
-rw-r--r--arch/x86/kernel/umip.c8
-rw-r--r--arch/x86/kernel/uprobes.c2
-rw-r--r--arch/x86/kvm/mmu.c11
-rw-r--r--arch/x86/mm/fault.c167
-rw-r--r--arch/x86/mm/mpx.c30
-rw-r--r--drivers/misc/genwqe/card_base.h2
-rw-r--r--drivers/misc/genwqe/card_dev.c9
-rw-r--r--drivers/tty/sysrq.c2
-rw-r--r--drivers/tty/tty_io.c6
-rw-r--r--drivers/usb/core/devio.c4
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c4
-rw-r--r--fs/binfmt_elf.c6
-rw-r--r--fs/coredump.c2
-rw-r--r--fs/fcntl.c2
-rw-r--r--fs/jffs2/background.c2
-rw-r--r--fs/signalfd.c6
-rw-r--r--include/linux/binfmts.h2
-rw-r--r--include/linux/compat.h4
-rw-r--r--include/linux/coredump.h4
-rw-r--r--include/linux/lsm_hooks.h4
-rw-r--r--include/linux/posix-timers.h2
-rw-r--r--include/linux/ptrace.h17
-rw-r--r--include/linux/sched.h2
-rw-r--r--include/linux/sched/signal.h23
-rw-r--r--include/linux/security.h6
-rw-r--r--include/linux/signal.h18
-rw-r--r--include/linux/signal_types.h8
-rw-r--r--include/linux/tracehook.h13
-rw-r--r--include/trace/events/signal.h7
-rw-r--r--include/uapi/asm-generic/siginfo.h193
-rw-r--r--ipc/mqueue.c2
-rw-r--r--kernel/events/uprobes.c4
-rw-r--r--kernel/pid_namespace.c2
-rw-r--r--kernel/ptrace.c26
-rw-r--r--kernel/seccomp.c6
-rw-r--r--kernel/signal.c421
-rw-r--r--kernel/time/posix-timers.c2
-rw-r--r--mm/oom_kill.c4
-rw-r--r--security/apparmor/lsm.c2
-rw-r--r--security/security.c2
-rw-r--r--security/selinux/hooks.c2
-rw-r--r--security/smack/smack_lsm.c2
-rw-r--r--virt/kvm/arm/mmu.c14
98 files changed, 925 insertions, 1328 deletions
diff --git a/arch/alpha/include/uapi/asm/siginfo.h b/arch/alpha/include/uapi/asm/siginfo.h
index db3f0138536f4..6e1a2af2f962d 100644
--- a/arch/alpha/include/uapi/asm/siginfo.h
+++ b/arch/alpha/include/uapi/asm/siginfo.h
@@ -2,7 +2,6 @@
#ifndef _ALPHA_SIGINFO_H
#define _ALPHA_SIGINFO_H
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
#define __ARCH_SI_TRAPNO
#include <asm-generic/siginfo.h>
diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c
index b123558bf0bb4..a7fcbc0d39432 100644
--- a/arch/arc/kernel/traps.c
+++ b/arch/arc/kernel/traps.c
@@ -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()
*/
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)) {
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 {
/* If not due to copy_(to|from)_user, we are doomed */
if (fixup_exception(regs))
return 0;
- die(str, regs, (unsigned long)info->si_addr);
+ die(str, regs, (unsigned long)addr);
}
return 1;
@@ -64,16 +65,9 @@ unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info)
#define DO_ERROR_INFO(signr, str, name, sicode) \
int name(unsigned long address, struct pt_regs *regs) \
-{ \
- siginfo_t info; \
- \
- 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);\
+{ \
+ return unhandled_exception(str, regs, signr, sicode, \
+ (void __user *)address); \
}
/*
diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c
index db6913094be3c..c9da6102eb4fb 100644
--- a/arch/arc/mm/fault.c
+++ b/arch/arc/mm/fault.c
@@ -66,14 +66,12 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
struct vm_area_struct *vma = NULL;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
- siginfo_t info;
+ int si_code;
int ret;
vm_fault_t fault;
int write = regs->ecr_cause & ECR_C_PROTV_STORE; /* ST/EX */
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
- clear_siginfo(&info);
-
/*
* We fault-in kernel-space virtual memory on-demand. The
* 'reference' page table is init_mm.pgd.
@@ -91,7 +89,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
return;
}
- info.si_code = SEGV_MAPERR;
+ si_code = SEGV_MAPERR;
/*
* If we're in an interrupt or have no user
@@ -119,7 +117,7 @@ retry:
* we can handle it..
*/
good_area:
- info.si_code = SEGV_ACCERR;
+ si_code = SEGV_ACCERR;
/* Handle protection violation, execute on heap or stack */
@@ -199,11 +197,7 @@ bad_area_nosemaphore:
/* User mode accesses just cause a SIGSEGV */
if (user_mode(regs)) {
tsk->thread.fault_address = address;
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* info.si_code has been set above */
- info.si_addr = (void __user *)address;
- force_sig_info(SIGSEGV, &info, tsk);
+ force_sig_fault(SIGSEGV, si_code, (void __user *)address, tsk);
return;
}
@@ -238,9 +232,5 @@ do_sigbus:
goto no_context;
tsk->thread.fault_address = address;
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_ADRERR;
- info.si_addr = (void __user *)address;
- force_sig_info(SIGBUS, &info, tsk);
+ force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, tsk);
}
diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h
index 237aa52d87339..36c951dd23b82 100644
--- a/arch/arm/include/asm/bug.h
+++ b/arch/arm/include/asm/bug.h
@@ -62,8 +62,8 @@ do { \
struct pt_regs;
void die(const char *msg, struct pt_regs *regs, int err);
-struct siginfo;
-void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
+void arm_notify_die(const char *str, struct pt_regs *regs,
+ int signo, int si_code, void __user *addr,
unsigned long err, unsigned long trap);
#ifdef CONFIG_ARM_LPAE
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 36718a4243589..6fa5b6387556d 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -203,15 +203,8 @@ void ptrace_disable(struct task_struct *child)
*/
void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
{
- siginfo_t info;
-
- 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);
+ force_sig_fault(SIGTRAP, TRAP_BRKPT,
+ (void __user *)instruction_pointer(regs), tsk);
}
static int break_trap(struct pt_regs *regs, unsigned int instr)
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c
index 80517f293eb9c..a188d5e8ab7fa 100644
--- a/arch/arm/kernel/swp_emulate.c
+++ b/arch/arm/kernel/swp_emulate.c
@@ -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)
{
- siginfo_t info;
+ int si_code;
- clear_siginfo(&info);
down_read(&current->mm->mmap_sem);
if (find_vma(current->mm, addr) == NULL)
- info.si_code = SEGV_MAPERR;
+ si_code = SEGV_MAPERR;
else
- info.si_code = SEGV_ACCERR;
+ si_code = SEGV_ACCERR;
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");
- 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++;
}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index badf02ca36938..2d668cff8ef43 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -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,
- 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)) {
current->thread.error_code = err;
current->thread.trap_no = trap;
- force_sig_info(info->si_signo, info, current);
+ force_sig_fault(signo, si_code, addr, current);
} else {
die(str, regs, err);
}
@@ -438,10 +439,8 @@ int call_undef_hook(struct pt_regs *regs, unsigned int instr)
asmlinkage void do_undefinstr(struct pt_regs *regs)
{
unsigned int instr;
- siginfo_t info;
void __user *pc;
- clear_siginfo(&info);
pc = (void __user *)instruction_pointer(regs);
if (processor_mode(regs) == SVC_MODE) {
@@ -485,13 +484,8 @@ die_sig:
dump_instr(KERN_INFO, regs);
}
#endif
-
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = ILL_ILLOPC;
- info.si_addr = pc;
-
- arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
+ arm_notify_die("Oops - undefined instruction", regs,
+ SIGILL, ILL_ILLOPC, pc, 0, 6);
}
NOKPROBE_SYMBOL(do_undefinstr)
@@ -539,9 +533,6 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason)
static int bad_syscall(int n, struct pt_regs *regs)
{
- siginfo_t info;
-
- clear_siginfo(&info);
if ((current->personality & PER_MASK) != PER_LINUX) {
send_sig(SIGSEGV, current, 1);
return regs->ARM_r0;
@@ -555,13 +546,10 @@ static int bad_syscall(int n, struct pt_regs *regs)
}
#endif
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = ILL_ILLTRP;
- info.si_addr = (void __user *)instruction_pointer(regs) -
- (thumb_mode(regs) ? 2 : 4);
-
- arm_notify_die("Oops - bad syscall", regs, &info, n, 0);
+ arm_notify_die("Oops - bad syscall", regs, SIGILL, ILL_ILLTRP,
+ (void __user *)instruction_pointer(regs) -
+ (thumb_mode(regs) ? 2 : 4),
+ n, 0);
return regs->ARM_r0;
}
@@ -607,20 +595,13 @@ do_cache_op(unsigned long start, unsigned long end, int flags)
#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
asmlinkage int arm_syscall(int no, struct pt_regs *regs)
{
- siginfo_t info;
-
- clear_siginfo(&info);
if ((no >> 16) != (__ARM_NR_BASE>> 16))
return bad_syscall(no, regs);
switch (no & 0xffff) {
case 0: /* branch through 0 */
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_code = SEGV_MAPERR;
- info.si_addr = NULL;
-
- arm_notify_die("branch through zero", regs, &info, 0, 0);
+ arm_notify_die("branch through zero", regs,
+ SIGSEGV, SEGV_MAPERR, NULL, 0, 0);
return 0;
case NR(breakpoint): /* SWI BREAK_POINT */
@@ -688,13 +669,10 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
}
}
#endif
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = ILL_ILLTRP;
- info.si_addr = (void __user *)instruction_pointer(regs) -
- (thumb_mode(regs) ? 2 : 4);
-
- arm_notify_die("Oops - bad syscall(2)", regs, &info, no, 0);
+ arm_notify_die("Oops - bad syscall(2)", regs, SIGILL, ILL_ILLTRP,
+ (void __user *)instruction_pointer(regs) -
+ (thumb_mode(regs) ? 2 : 4),
+ no, 0);
return 0;
}
@@ -744,9 +722,6 @@ asmlinkage void
baddataabort(int code, unsigned long instr, struct pt_regs *regs)
{
unsigned long addr = instruction_pointer(regs);
- siginfo_t info;
-
- clear_siginfo(&info);
#ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_BADABORT) {
@@ -757,12 +732,8 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
}
#endif
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = ILL_ILLOPC;
- info.si_addr = (void __user *)addr;
-
- arm_notify_die("unknown data abort code", regs, &info, instr, 0);
+ arm_notify_die("unknown data abort code", regs,
+ SIGILL, ILL_ILLOPC, (void __user *)addr, instr, 0);
}
void __readwrite_bug(const char *fn)
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index bd2c739d80839..b54f8f8def362 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -948,15 +948,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
goto fixup;
if (ai_usermode & UM_SIGNAL) {
- siginfo_t si;
-
- 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);
+ force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr, current);
} else {
/*
* We're about to disable the alignment trap and return to
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 3232afb6fdc00..f4ea4c62c613c 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -161,13 +161,9 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
unsigned int fsr, unsigned int sig, int code,
struct pt_regs *regs)
{
- struct siginfo si;
-
if (addr > TASK_SIZE)
harden_branch_predictor();
- clear_siginfo(&si);
-
#ifdef CONFIG_DEBUG_USER
if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
((user_debug & UDBG_BUS) && (sig == SIGBUS))) {
@@ -181,11 +177,7 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
tsk->thread.address = addr;
tsk->thread.error_code = fsr;
tsk->thread.trap_no = 14;
- si.si_signo = sig;
- si.si_errno = 0;
- si.si_code = code;
- si.si_addr = (void __user *)addr;
- force_sig_info(sig, &si, tsk);
+ force_sig_fault(sig, code, (void __user *)addr, tsk);
}
void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
@@ -554,7 +546,6 @@ asmlinkage void
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
- struct siginfo info;
if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
return;
@@ -563,12 +554,8 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
inf->name, fsr, addr);
show_pte(current->mm, addr);
- clear_siginfo(&info);
- info.si_signo = inf->sig;
- info.si_errno = 0;
- info.si_code = inf->code;
- info.si_addr = (void __user *)addr;
- arm_notify_die("", regs, &info, fsr, 0);
+ arm_notify_die("", regs, inf->sig, inf->code, (void __user *)addr,
+ fsr, 0);
}
void __init
@@ -588,7 +575,6 @@ asmlinkage void
do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
{
const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
- struct siginfo info;
if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
return;
@@ -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",
inf->name, ifsr, addr);
- clear_siginfo(&info);
- info.si_signo = inf->sig;
- info.si_errno = 0;
- info.si_code = inf->code;
- info.si_addr = (void __user *)addr;
- arm_notify_die("", regs, &info, ifsr, 0);
+ arm_notify_die("", regs, inf->sig, inf->code, (void __user *)addr,
+ ifsr, 0);
}
/*
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 2b287d0d6bc2d..aff6e6eadc700 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -216,13 +216,6 @@ static struct notifier_block vfp_notifier_block = {
*/
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 used for
@@ -230,7 +223,9 @@ static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
current->thread.error_code = 0;
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)
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index 28893a0b141d2..0e2a0ecaf4842 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -33,7 +33,8 @@ void die(const char *msg, struct pt_regs *regs, int err);
struct siginfo;
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,
struct pt_regs *),
diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
index c320f3bf6c57c..f9c1aa6167d25 100644
--- a/arch/arm64/include/asm/traps.h
+++ b/arch/arm64/include/asm/traps.h
@@ -37,8 +37,9 @@ void register_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 arm64_notify_segfault(unsigned long addr);
-void arm64_force_sig_info(struct siginfo *info, const char *str,
- struct task_struct *tsk);
+void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str);
+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
diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
index 198afbf0688f6..6c5adf4586903 100644
--- a/arch/arm64/include/uapi/asm/Kbuild
+++ b/arch/arm64/include/uapi/asm/Kbuild
@@ -19,3 +19,4 @@ generic-y += swab.h
generic-y += termbits.h
generic-y += termios.h
generic-y += types.h
+generic-y += siginfo.h
diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
deleted file mode 100644
index 574d12f860397..0000000000000
--- a/arch/arm64/include/uapi/asm/siginfo.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 06ca574495af9..d7bb6aefae0a8 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -210,13 +210,6 @@ NOKPROBE_SYMBOL(call_step_hook);
static void send_user_sigtrap(int si_code)
{
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)))
return;
@@ -224,7 +217,9 @@ static void send_user_sigtrap(int si_code)
if (interrupts_enabled(regs))
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,
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 58c53bc969289..5ebe73b699618 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -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)
{
- siginfo_t info;
unsigned int si_code = FPE_FLTUNK;
if (esr & ESR_ELx_FP_EXC_TFV) {
@@ -858,12 +857,9 @@ asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
si_code = FPE_FLTRES;
}
- clear_siginfo(&info);
- info.si_signo = SIGFPE;
- info.si_code = si_code;
- info.si_addr = (void __user *)instruction_pointer(regs);
-
- send_sig_info(SIGFPE, &info, current);
+ send_sig_fault(SIGFPE, si_code,
+ (void __user *)instruction_pointer(regs),
+ current);
}
void fpsimd_thread_switch(struct task_struct *next)
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 6219486fa25fa..1710a2d016694 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -182,13 +182,7 @@ static void ptrace_hbptriggered(struct perf_event *bp,
struct pt_regs *regs)
{
struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
- siginfo_t info;
-
- clear_siginfo(&info);
- info.si_signo = SIGTRAP;
- info.si_errno = 0;
- info.si_code = TRAP_HWBKPT;
- info.si_addr = (void __user *)(bkpt->trigger);
+ const char *desc = "Hardware breakpoint trap (ptrace)";
#ifdef CONFIG_COMPAT
if (is_compat_task()) {
@@ -208,10 +202,14 @@ static void ptrace_hbptriggered(struct perf_event *bp,
break;
}
}
- force_sig_ptrace_errno_trap(si_errno, (void __user *)bkpt->trigger);
+ arm64_force_sig_ptrace_errno_trap(si_errno,
+ (void __user *)bkpt->trigger,
+ desc);
}
#endif
- arm64_force_sig_info(&info, "Hardware breakpoint trap (ptrace)", current);
+ arm64_force_sig_fault(SIGTRAP, TRAP_HWBKPT,
+ (void __user *)(bkpt->trigger),
+ desc);
}
/*
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c
index a6109825eeb97..32653d156747e 100644
--- a/arch/arm64/kernel/sys_compat.c
+++ b/arch/arm64/kernel/sys_compat.c
@@ -68,8 +68,8 @@ do_compat_cache_op(unsigned long start, unsigned long end, int flags)
*/
long compat_arm_syscall(struct pt_regs *regs)
{
- siginfo_t info;
unsigned int no = regs->regs[7];
+ void __user *addr;
switch (no) {
/*
@@ -112,13 +112,10 @@ long compat_arm_syscall(struct pt_regs *regs)
break;
}
- clear_siginfo(&info);
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = ILL_ILLTRP;
- info.si_addr = (void __user *)instruction_pointer(regs) -
- (compat_thumb_mode(regs) ? 2 : 4);
+ addr = (void __user *)instruction_pointer(regs) -
+ (compat_thumb_mode(regs) ? 2 : 4);
- arm64_notify_die("Oops - bad compat syscall(2)", regs, &info, no);
+ arm64_notify_die("Oops - bad compat syscall(2)", regs,
+ SIGILL, ILL_ILLTRP, addr, no);
return 0;
}
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 4066da7f1e5ee..5f4d9acb32f50 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -224,24 +224,19 @@ void die(const char *str, struct pt_regs *regs, int err)
do_exit(SIGSEGV);
}
-static bool show_unhandled_signals_ratelimited(void)
+static void arm64_show_signal(int signo, const char *str)
{
static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
- return show_unhandled_signals && __ratelimit(&rs);
-}
-
-void arm64_force_sig_info(struct siginfo *info, const char *str,
- struct task_struct *tsk)
-{
+ struct task_struct *tsk = current;
unsigned int esr = tsk->thread.fault_code;
struct pt_regs *regs = task_pt_regs(tsk);
- if (!unhandled_signal(tsk, info->si_signo))
- goto send_sig;
-
- if (!show_unhandled_signals_ratelimited())
- goto send_sig;
+ /* Leave if the signal won't be shown */
+ if (!show_unhandled_signals ||
+ !unhandled_signal(tsk, signo) ||
+ !__ratelimit(&rs))
+ return;
pr_info("%s[%d]: unhandled exception: ", tsk->comm, task_pid_nr(tsk));
if (esr)
@@ -251,19 +246,39 @@ void arm64_force_sig_info(struct siginfo *info, const char *str,
print_vma_addr(KERN_CONT " in ", regs->pc);
pr_cont("\n");
__show_regs(regs);
+}
+
+void arm64_force_sig_fault(int signo, int code, void __user *addr,
+ const char *str)
+{
+ arm64_show_signal(signo, str);
+ force_sig_fault(signo, code, addr, current);
+}
-send_sig:
- force_sig_info(info->si_signo, info, tsk);
+void arm64_force_sig_mceerr(int code, void __user *addr, short lsb,
+ const char *str)
+{
+ arm64_show_signal(SIGBUS, str);
+ force_sig_mceerr(code, addr, lsb, current);
+}
+
+void arm64_force_sig_ptrace_errno_trap(int errno, void __user *addr,
+ const char *str)
+{
+ arm64_show_signal(SIGTRAP, str);
+ force_sig_ptrace_errno_trap(errno, addr);
}
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)
{
if (user_mode(regs)) {
WARN_ON(regs != current_pt_regs());
current->thread.fault_address = 0;
current->thread.fault_code = err;
- arm64_force_sig_info(info, str, current);
+
+ arm64_force_sig_fault(signo, sicode, addr, str);
} else {
die(str, regs, err);
}
@@ -350,15 +365,12 @@ exit:
void force_signal_inject(int signal, int code, unsigned long address)
{
- siginfo_t info;
const char *desc;
struct pt_regs *regs = current_pt_regs();
if (WARN_ON(!user_mode(regs)))
return;
- clear_siginfo(&info);
-
switch (signal) {
case SIGILL:
desc = "undefined instruction";
@@ -377,12 +389,7 @@ void force_signal_inject(int signal, int code, unsigned long address)
signal = SIGKILL;
}
- info.si_signo = signal;
- info.si_errno = 0;
- info.si_code = code;
- info.si_addr = (void __user *)address;
-
- arm64_notify_die(desc, regs, &info, 0);
+ arm64_notify_die(desc, regs, signal, code, (void __user *)address, 0);
}
/*
@@ -799,19 +806,13 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
*/
asmlinkage void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
{
- siginfo_t info;
void __user *pc = (void __user *)instruction_pointer(regs);
- clear_siginfo(&info);
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = ILL_ILLOPC;
- info.si_addr = pc;
-
current->thread.fault_address = 0;
current->thread.fault_code = esr;
- arm64_force_sig_info(&info, "Bad EL0 synchronous exception", current);
+ arm64_force_sig_fault(SIGILL, ILL_ILLOPC, pc,
+ "Bad EL0 synchronous exception");
}
#ifdef CONFIG_VMAP_STACK
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index d0e638ef3af62..7d9571f4ae3d6 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -303,9 +303,9 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr,
die_kernel_fault(msg, addr, esr, regs);
}
-static void __do_user_fault(struct siginfo *info, unsigned int esr)
+static void set_thread_esr(unsigned long address, unsigned int esr)
{
- current->thread.fault_address = (unsigned long)info->si_addr;
+ current->thread.fault_address = address;
/*
* If the faulting address is in the kernel, we must sanitize the ESR.
@@ -358,7 +358,6 @@ static void __do_user_fault(struct siginfo *info, unsigned int esr)
}
current->thread.fault_code = esr;
- arm64_force_sig_info(info, esr_to_fault_info(esr)->name, current);
}
static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs)
@@ -369,14 +368,10 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re
*/
if (user_mode(regs)) {
const struct fault_info *inf = esr_to_fault_info(esr);
- struct siginfo si;
- clear_siginfo(&si);
- si.si_signo = inf->sig;
- si.si_code = inf->code;
- si.si_addr = (void __user *)addr;
-
- __do_user_fault(&si, esr);
+ set_thread_esr(addr, esr);
+ arm64_force_sig_fault(inf->sig, inf->code, (void __user *)addr,
+ inf->name);
} else {
__do_kernel_fault(addr, esr, regs);
}
@@ -430,9 +425,9 @@ static bool is_el0_instruction_abort(unsigned int esr)
static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
struct pt_regs *regs)
{
+ const struct fault_info *inf;
struct task_struct *tsk;
struct mm_struct *mm;
- struct siginfo si;
vm_fault_t fault, major = 0;
unsigned long vm_flags = VM_READ | VM_WRITE;
unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
@@ -568,37 +563,35 @@ retry:
return 0;
}
- clear_siginfo(&si);
- si.si_addr = (void __user *)addr;
-
+ inf = esr_to_fault_info(esr);
+ set_thread_esr(addr, esr);
if (fault & VM_FAULT_SIGBUS) {
/*
* We had some memory, but were unable to successfully fix up
* this page fault.
*/
- si.si_signo = SIGBUS;
- si.si_code = BUS_ADRERR;
- } else if (fault & VM_FAULT_HWPOISON_LARGE) {
- unsigned int hindex = VM_FAULT_GET_HINDEX(fault);
-
- si.si_signo = SIGBUS;
- si.si_code = BUS_MCEERR_AR;
- si.si_addr_lsb = hstate_index_to_shift(hindex);
- } else if (fault & VM_FAULT_HWPOISON) {
- si.si_signo = SIGBUS;
- si.si_code = BUS_MCEERR_AR;
- si.si_addr_lsb = PAGE_SHIFT;
+ arm64_force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)addr,
+ inf->name);
+ } else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) {
+ unsigned int lsb;
+
+ lsb = PAGE_SHIFT;
+ if (fault & VM_FAULT_HWPOISON_LARGE)
+ lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
+
+ arm64_force_sig_mceerr(BUS_MCEERR_AR, (void __user *)addr, lsb,
+ inf->name);
} else {
/*
* Something tried to access memory that isn't in our memory
* map.
*/
- si.si_signo = SIGSEGV;
- si.si_code = fault == VM_FAULT_BADACCESS ?
- SEGV_ACCERR : SEGV_MAPERR;
+ arm64_force_sig_fault(SIGSEGV,
+ fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR,
+ (void __user *)addr,
+ inf->name);
}
- __do_user_fault(&si, esr);
return 0;
no_context:
@@ -631,8 +624,8 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
{
- struct siginfo info;
const struct fault_info *inf;
+ void __user *siaddr;
inf = esr_to_fault_info(esr);
@@ -651,15 +644,11 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
nmi_exit();
}
- clear_siginfo(&info);
- info.si_signo = inf->sig;
- info.si_errno = 0;
- info.si_code = inf->code;
if (esr & ESR_ELx_FnV)
- info.si_addr = NULL;
+ siaddr = NULL;
else
- info.si_addr = (void __user *)addr;
- arm64_notify_die(inf->name, regs, &info, esr);
+ siaddr = (void __user *)addr;
+ arm64_notify_die(inf->name, regs, inf->sig, inf->code, siaddr, esr);
return 0;
}
@@ -740,7 +729,6 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
struct pt_regs *regs)
{
const struct fault_info *inf = esr_to_fault_info(esr);
- struct siginfo info;
if (!inf->fn(addr, esr, regs))
return;
@@ -751,12 +739,8 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
show_pte(addr);
}
- clear_siginfo(&info);
- info.si_signo = inf->sig;
- info.si_errno = 0;
- info.si_code = inf->code;
- info.si_addr = (void __user *)addr;
- arm64_notify_die(inf->name, regs, &info, esr);
+ arm64_notify_die(inf->name, regs,
+ inf->sig, inf->code, (void __user *)addr, esr);
}
asmlinkage void __exception do_el0_irq_bp_hardening(void)
@@ -786,20 +770,14 @@ asmlinkage void __exception do_sp_pc_abort(unsigned long addr,
unsigned int esr,
struct pt_regs *regs)
{
- struct siginfo info;
-
if (user_mode(regs)) {
if (instruction_pointer(regs) > TASK_SIZE)
arm64_apply_bp_hardening();
local_daif_restore(DAIF_PROCCTX);
}
- clear_siginfo(&info);
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_ADRALN;
- info.si_addr = (void __user *)addr;
- arm64_notify_die("SP/PC alignment exception", regs, &info, esr);
+ arm64_notify_die("SP/PC alignment exception", regs,
+ SIGBUS, BUS_ADRALN, (void __user *)addr, esr);
}
int __init early_brk64(unsigned long addr, unsigned int esr,
@@ -853,14 +831,8 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
if (!inf->fn(addr, esr, regs)) {
rv = 1;
} else {
- struct siginfo info;
-
- clear_siginfo(&info);
- info.si_signo = inf->sig;
- info.si_errno = 0;
- info.si_code = inf->code;
- info.si_addr = (void __user *)addr;
- arm64_notify_die(inf->name, regs, &info, esr);
+ arm64_notify_die(inf->name, regs,
+ inf->sig, inf->code, (void __user *)addr, esr);
rv = 0;
}
diff --git a/arch/ia64/include/uapi/asm/siginfo.h b/arch/ia64/include/uapi/asm/siginfo.h
index 52b5af4245116..796af1ccaa7e4 100644
--- a/arch/ia64/include/uapi/asm/siginfo.h
+++ b/arch/ia64/include/uapi/asm/siginfo.h
@@ -9,8 +9,6 @@
#define _UAPI_ASM_IA64_SIGINFO_H
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
-
#include <asm-generic/siginfo.h>
#define si_imm _sifields._sigfault._imm /* as per UNIX SysV ABI spec */
diff --git a/arch/ia64/kernel/brl_emu.c b/arch/ia64/kernel/brl_emu.c
index a61f6c6a36f83..c0239bf77a09e 100644
--- a/arch/ia64/kernel/brl_emu.c
+++ b/arch/ia64/kernel/brl_emu.c
@@ -58,11 +58,9 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec)
unsigned long bundle[2];
unsigned long opcode, btype, qp, offset, cpl;
unsigned long next_ip;
- struct siginfo siginfo;
struct illegal_op_return rv;
long tmp_taken, unimplemented_address;
- clear_siginfo(&siginfo);
rv.fkt = (unsigned long) -1;
/*
@@ -198,39 +196,22 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec)
* The target address contains unimplemented bits.
*/
printk(KERN_DEBUG "Woah! Unimplemented Instruction Address Trap!\n");
- siginfo.si_signo = SIGILL;
- siginfo.si_errno = 0;
- siginfo.si_flags = 0;
- siginfo.si_isr = 0;
- siginfo.si_imm = 0;
- siginfo.si_code = ILL_BADIADDR;
- force_sig_info(SIGILL, &siginfo, current);
+ force_sig_fault(SIGILL, ILL_BADIADDR, (void __user *)NULL,
+ 0, 0, 0, current);
} else if (ia64_psr(regs)->tb) {
/*
* Branch Tracing is enabled.
* Force a taken branch signal.
*/
- siginfo.si_signo = SIGTRAP;
- siginfo.si_errno = 0;
- siginfo.si_code = TRAP_BRANCH;
- siginfo.si_flags = 0;
- siginfo.si_isr = 0;
- siginfo.si_addr = 0;
- siginfo.si_imm = 0;
- force_sig_info(SIGTRAP, &siginfo, current);
+ force_sig_fault(SIGTRAP, TRAP_BRANCH, (void __user *)NULL,
+ 0, 0, 0, current);
} else if (ia64_psr(regs)->ss) {
/*
* Single Step is enabled.
* Force a trace signal.
*/
- siginfo.si_signo = SIGTRAP;
- siginfo.si_errno = 0;
- siginfo.si_code = TRAP_TRACE;
- siginfo.si_flags = 0;
- siginfo.si_isr = 0;
- siginfo.si_addr = 0;
- siginfo.si_imm = 0;
- force_sig_info(SIGTRAP, &siginfo, current);
+ force_sig_fault(SIGTRAP, TRAP_TRACE, (void __user *)NULL,
+ 0, 0, 0, current);
}
return rv;
}
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index d1234a5ba4c55..9a960829a01d9 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -110,7 +110,6 @@ ia64_rt_sigreturn (struct sigscratch *scr)
{
extern char ia64_strace_leave_kernel, ia64_leave_kernel;
struct sigcontext __user *sc;
- struct siginfo si;
sigset_t set;
long retval;
@@ -153,14 +152,7 @@ ia64_rt_sigreturn (struct sigscratch *scr)
return retval;
give_sigsegv:
- clear_siginfo(&si);
- si.si_signo = SIGSEGV;
- si.si_errno = 0;
- si.si_code = SI_KERNEL;
- si.si_pid = task_pid_vnr(current);
- si.si_uid = from_kuid_munged(current_user_ns(), current_uid());
- si.si_addr = sc;
- force_sig_info(SIGSEGV, &si, current);
+ force_sig(SIGSEGV, current);
return retval;
}
@@ -232,37 +224,6 @@ rbs_on_sig_stack (unsigned long bsp)
}
static long
-force_sigsegv_info (int sig, void __user *addr)
-{
- unsigned long flags;
- struct siginfo si;
-
- clear_siginfo(&si);
- if (sig == SIGSEGV) {
- /*
- * Acquiring siglock around the sa_handler-update is almost
- * certainly overkill, but this isn't a
- * performance-critical path and I'd rather play it safe
- * here than having to debug a nasty race if and when
- * something changes in kernel/signal.c that would make it
- * no longer safe to modify sa_handler without holding the
- * lock.
- */
- spin_lock_irqsave(&current->sighand->siglock, flags);
- current->sighand->action[sig - 1].sa.sa_handler = SIG_DFL;
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
- }
- si.si_signo = SIGSEGV;
- si.si_errno = 0;
- si.si_code = SI_KERNEL;
- si.si_pid = task_pid_vnr(current);
- si.si_uid = from_kuid_munged(current_user_ns(), current_uid());
- si.si_addr = addr;
- force_sig_info(SIGSEGV, &si, current);
- return 1;
-}
-
-static long
setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr)
{
extern char __kernel_sigtramp[];
@@ -295,15 +256,18 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr)
* instead so we will die with SIGSEGV.
*/
check_sp = (new_sp - sizeof(*frame)) & -STACK_ALIGN;
- if (!likely(on_sig_stack(check_sp)))
- return force_sigsegv_info(ksig->sig, (void __user *)
- check_sp);
+ if (!likely(on_sig_stack(check_sp))) {
+ force_sigsegv(ksig->sig, current);
+ return 1;
+ }
}
}
frame = (void __user *) ((new_sp - sizeof(*frame)) & -STACK_ALIGN);
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- return force_sigsegv_info(ksig->sig, frame);
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
+ force_sigsegv(ksig->sig, current);
+ return 1;
+ }
err = __put_user(ksig->sig, &frame->arg0);
err |= __put_user(&frame->info, &frame->arg1);
@@ -317,8 +281,10 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct sigscratch *scr)
err |= __save_altstack(&frame->sc.sc_stack, scr->pt.r12);
err |= setup_sigcontext(&frame->sc, set, scr);
- if (unlikely(err))
- return force_sigsegv_info(ksig->sig, frame);
+ if (unlikely(err)) {
+ force_sigsegv(ksig->sig, current);
+ return 1;
+ }
scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */
scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index c6f4932073a18..85d8616ac4f6e 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -100,16 +100,8 @@ die_if_kernel (char *str, struct pt_regs *regs, long err)
void
__kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
{
- siginfo_t siginfo;
int sig, code;
- /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */
- clear_siginfo(&siginfo);
- siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri);
- siginfo.si_imm = break_num;
- siginfo.si_flags = 0; /* clear __ISR_VALID */
- siginfo.si_isr = 0;
-
switch (break_num) {
case 0: /* unknown error (used by GCC for __builtin_abort()) */
if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP)
@@ -182,10 +174,9 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
sig = SIGTRAP; code = TRAP_BRKPT;
}
}
- siginfo.si_signo = sig;
- siginfo.si_errno = 0;
- siginfo.si_code = code;
- force_sig_info(sig, &siginfo, current);
+ force_sig_fault(sig, code,
+ (void __user *) (regs->cr_iip + ia64_psr(regs)->ri),
+ break_num, 0 /* clear __ISR_VALID */, 0, current);
}
/*
@@ -344,30 +335,25 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
printk(KERN_ERR "handle_fpu_swa: fp_emulate() returned -1\n");
return -1;
} else {
- struct siginfo siginfo;
-
/* is next instruction a trap? */
+ int si_code;
+
if (exception & 2) {
ia64_increment_ip(regs);
}
- clear_siginfo(&siginfo);
- siginfo.si_signo = SIGFPE;
- siginfo.si_errno = 0;
- siginfo.si_code = FPE_FLTUNK; /* default code */
- siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri);
+ si_code = FPE_FLTUNK; /* default code */
if (isr & 0x11) {
- siginfo.si_code = FPE_FLTINV;
+ si_code = FPE_FLTINV;
} else if (isr & 0x22) {
/* denormal operand gets the same si_code as underflow
* see arch/i386/kernel/traps.c:math_error() */
- siginfo.si_code = FPE_FLTUND;
+ si_code = FPE_FLTUND;
} else if (isr & 0x44) {
- siginfo.si_code = FPE_FLTDIV;
+ si_code = FPE_FLTDIV;
}
- siginfo.si_isr = isr;
- siginfo.si_flags = __ISR_VALID;
- siginfo.si_imm = 0;
- force_sig_info(SIGFPE, &siginfo, current);
+ force_sig_fault(SIGFPE, si_code,
+ (void __user *) (regs->cr_iip + ia64_psr(regs)->ri),
+ 0, __ISR_VALID, isr, current);
}
} else {
if (exception == -1) {
@@ -375,24 +361,19 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
return -1;
} else if (exception != 0) {
/* raise exception */
- struct siginfo siginfo;
+ int si_code;
- clear_siginfo(&siginfo);
- siginfo.si_signo = SIGFPE;
- siginfo.si_errno = 0;
- siginfo.si_code = FPE_FLTUNK; /* default code */
- siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri);
+ si_code = FPE_FLTUNK; /* default code */
if (isr & 0x880) {
- siginfo.si_code = FPE_FLTOVF;
+ si_code = FPE_FLTOVF;
} else if (isr & 0x1100) {
- siginfo.si_code = FPE_FLTUND;
+ si_code = FPE_FLTUND;
} else if (isr & 0x2200) {
- siginfo.si_code = FPE_FLTRES;
+ si_code = FPE_FLTRES;
}
- siginfo.si_isr = isr;
- siginfo.si_flags = __ISR_VALID;
- siginfo.si_imm = 0;
- force_sig_info(SIGFPE, &siginfo, current);
+ force_sig_fault(SIGFPE, si_code,
+ (void __user *) (regs->cr_iip + ia64_psr(regs)->ri),
+ 0, __ISR_VALID, isr, current);
}
}
return 0;
@@ -408,7 +389,6 @@ ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3,
struct pt_regs regs)
{
struct illegal_op_return rv;
- struct siginfo si;
char buf[128];
#ifdef CONFIG_IA64_BRL_EMU
@@ -426,11 +406,9 @@ ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3,
if (die_if_kernel(buf, &regs, 0))
return rv;
- clear_siginfo(&si);
- si.si_signo = SIGILL;
- si.si_code = ILL_ILLOPC;
- si.si_addr = (void __user *) (regs.cr_iip + ia64_psr(&regs)->ri);
- force_sig_info(SIGILL, &si, current);
+ force_sig_fault(SIGILL, ILL_ILLOPC,
+ (void __user *) (regs.cr_iip + ia64_psr(&regs)->ri),
+ 0, 0, 0, current);
return rv;
}
@@ -441,7 +419,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
{
unsigned long code, error = isr, iip;
char buf[128];
- int result, sig;
+ int result, sig, si_code;
static const char *reason[] = {
"IA-64 Illegal Operation fault",
"IA-64 Privileged Operation fault",
@@ -490,7 +468,6 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
case 26: /* NaT Consumption */
if (user_mode(&regs)) {
- struct siginfo siginfo;
void __user *addr;
if (((isr >> 4) & 0xf) == 2) {
@@ -505,15 +482,8 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
addr = (void __user *) (regs.cr_iip
+ ia64_psr(&regs)->ri);
}
- clear_siginfo(&siginfo);
- siginfo.si_signo = sig;
- siginfo.si_code = code;
- siginfo.si_errno = 0;
- siginfo.si_addr = addr;
- siginfo.si_imm = vector;
- siginfo.si_flags = __ISR_VALID;
- siginfo.si_isr = isr;
- force_sig_info(sig, &siginfo, current);
+ force_sig_fault(sig, code, addr,
+ vector, __ISR_VALID, isr, current);
return;
} else if (ia64_done_with_exception(&regs))
return;
@@ -522,17 +492,8 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
case 31: /* Unsupported Data Reference */
if (user_mode(&regs)) {
- struct siginfo siginfo;
-
- clear_siginfo(&siginfo);
- siginfo.si_signo = SIGILL;
- siginfo.si_code = ILL_ILLOPN;
- siginfo.si_errno = 0;
- siginfo.si_addr = (void __user *) iip;
- siginfo.si_imm = vector;
- siginfo.si_flags = __ISR_VALID;
- siginfo.si_isr = isr;
- force_sig_info(SIGILL, &siginfo, current);
+ force_sig_fault(SIGILL, ILL_ILLOPN, (void __user *) iip,
+ vector, __ISR_VALID, isr, current);
return;
}
sprintf(buf, "Unsupported data reference");
@@ -541,10 +502,6 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
case 29: /* Debug */
case 35: /* Taken Branch Trap */
case 36: /* Single Step Trap */
- {
- struct siginfo siginfo;
-
- clear_siginfo(&siginfo);
if (fsys_mode(current, &regs)) {
extern char __kernel_syscall_via_break[];
/*
@@ -568,7 +525,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
switch (vector) {
default:
case 29:
- siginfo.si_code = TRAP_HWBKPT;
+ si_code = TRAP_HWBKPT;
#ifdef CONFIG_ITANIUM
/*
* Erratum 10 (IFA may contain incorrect address) now has
@@ -578,37 +535,22 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
ifa = regs.cr_iip;
#endif
break;
- case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
- case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
+ case 35: si_code = TRAP_BRANCH; ifa = 0; break;
+ case 36: si_code = TRAP_TRACE; ifa = 0; break;
}
- if (notify_die(DIE_FAULT, "ia64_fault", &regs, vector, siginfo.si_code, SIGTRAP)
+ if (notify_die(DIE_FAULT, "ia64_fault", &regs, vector, si_code, SIGTRAP)
== NOTIFY_STOP)
return;
- siginfo.si_signo = SIGTRAP;
- siginfo.si_errno = 0;
- siginfo.si_addr = (void __user *) ifa;
- siginfo.si_imm = 0;
- siginfo.si_flags = __ISR_VALID;
- siginfo.si_isr = isr;
- force_sig_info(SIGTRAP, &siginfo, current);
+ force_sig_fault(SIGTRAP, si_code, (void __user *) ifa,
+ 0, __ISR_VALID, isr, current);
return;
- }
case 32: /* fp fault */
case 33: /* fp trap */
result = handle_fpu_swa((vector == 32) ? 1 : 0, &regs, isr);
if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) {
- struct siginfo siginfo;
-
- clear_siginfo(&siginfo);
- siginfo.si_signo = SIGFPE;
- siginfo.si_errno = 0;
- siginfo.si_code = FPE_FLTINV;
- siginfo.si_addr = (void __user *) iip;
- siginfo.si_flags = __ISR_VALID;
- siginfo.si_isr = isr;
- siginfo.si_imm = 0;
- force_sig_info(SIGFPE, &siginfo, current);
+ force_sig_fault(SIGFPE, FPE_FLTINV, (void __user *) iip,
+ 0, __ISR_VALID, isr, current);
}
return;
@@ -634,17 +576,9 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
} else {
/* Unimplemented Instr. Address Trap */
if (user_mode(&regs)) {
- struct siginfo siginfo;
-
- clear_siginfo(&siginfo);
- siginfo.si_signo = SIGILL;
- siginfo.si_code = ILL_BADIADDR;
- siginfo.si_errno = 0;
- siginfo.si_flags = 0;
- siginfo.si_isr = 0;
- siginfo.si_imm = 0;
- siginfo.si_addr = (void __user *) iip;
- force_sig_info(SIGILL, &siginfo, current);
+ force_sig_fault(SIGILL, ILL_BADIADDR,
+ (void __user *) iip,
+ 0, 0, 0, current);
return;
}
sprintf(buf, "Unimplemented Instruction Address fault");
diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
index e309f9859acc3..a167a3824b35b 100644
--- a/arch/ia64/kernel/unaligned.c
+++ b/arch/ia64/kernel/unaligned.c
@@ -1298,7 +1298,6 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
mm_segment_t old_fs = get_fs();
unsigned long bundle[2];
unsigned long opcode;
- struct siginfo si;
const struct exception_table_entry *eh = NULL;
union {
unsigned long l;
@@ -1537,14 +1536,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
/* NOT_REACHED */
}
force_sigbus:
- clear_siginfo(&si);
- si.si_signo = SIGBUS;
- si.si_errno = 0;
- si.si_code = BUS_ADRALN;
- si.si_addr = (void __user *) ifa;
- si.si_flags = 0;
- si.si_isr = 0;
- si.si_imm = 0;
- force_sig_info(SIGBUS, &si, current);
+ force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *) ifa,
+ 0, 0, 0, current);
goto done;
}
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index a9d55ad8d67be..5baeb022f4742 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -248,16 +248,8 @@ retry:
return;
}
if (user_mode(regs)) {
- struct siginfo si;
-
- clear_siginfo(&si);
- si.si_signo = signal;
- si.si_errno = 0;
- si.si_code = code;
- si.si_addr = (void __user *) address;
- si.si_isr = isr;
- si.si_flags = __ISR_VALID;
- force_sig_info(signal, &si, current);
+ force_sig_fault(signal, code, (void __user *) address,
+ 0, __ISR_VALID, isr, current);
return;
}
diff --git a/arch/mips/include/uapi/asm/siginfo.h b/arch/mips/include/uapi/asm/siginfo.h
index 262504bd59a5f..c34c7eef0a1c1 100644
--- a/arch/mips/include/uapi/asm/siginfo.h
+++ b/arch/mips/include/uapi/asm/siginfo.h
@@ -14,17 +14,6 @@
#define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(long) + 2*sizeof(int))
#undef __ARCH_SI_TRAPNO /* exception code needs to fill this ... */
-/*
- * Careful to keep union _sifields from shifting ...
- */
-#if _MIPS_SZLONG == 32
-#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
-#elif _MIPS_SZLONG == 64
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
-#else
-#error _MIPS_SZLONG neither 32 nor 64
-#endif
-
#define __ARCH_HAS_SWAPPED_SIGINFO
#include <asm-generic/siginfo.h>
diff --git a/arch/parisc/include/uapi/asm/Kbuild b/arch/parisc/include/uapi/asm/Kbuild
index 286ef5a5904b0..adb5c64831c7e 100644
--- a/arch/parisc/include/uapi/asm/Kbuild
+++ b/arch/parisc/include/uapi/asm/Kbuild
@@ -7,3 +7,4 @@ generic-y += kvm_para.h
generic-y += param.h
generic-y += poll.h
generic-y += resource.h
+generic-y += siginfo.h
diff --git a/arch/parisc/include/uapi/asm/siginfo.h b/arch/parisc/include/uapi/asm/siginfo.h
deleted file mode 100644
index 4a1062e05aaff..0000000000000
--- a/arch/parisc/include/uapi/asm/siginfo.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _PARISC_SIGINFO_H
-#define _PARISC_SIGINFO_H
-
-#if defined(__LP64__)
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
-#endif
-
-#include <asm-generic/siginfo.h>
-
-#endif
diff --git a/arch/powerpc/include/asm/bug.h b/arch/powerpc/include/asm/bug.h
index fd06dbe7d7d32..fed7e6241349c 100644
--- a/arch/powerpc/include/asm/bug.h
+++ b/arch/powerpc/include/asm/bug.h
@@ -133,7 +133,7 @@ struct pt_regs;
extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
extern void bad_page_fault(struct pt_regs *, unsigned long, int);
extern void _exception(int, struct pt_regs *, int, unsigned long);
-extern void _exception_pkey(int, struct pt_regs *, int, unsigned long, int);
+extern void _exception_pkey(struct pt_regs *, unsigned long, int);
extern void die(const char *, struct pt_regs *, long);
extern bool die_will_crash(void);
extern void panic_flush_kmsg_start(void);
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index 447cbd1bee99f..5b480e1d5909f 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -149,7 +149,7 @@ do { \
#define arch_has_single_step() (1)
#define arch_has_block_step() (!cpu_has_feature(CPU_FTR_601))
-#define ARCH_HAS_USER_SINGLE_STEP_INFO
+#define ARCH_HAS_USER_SINGLE_STEP_REPORT
/*
* kprobe-based event tracer support
diff --git a/arch/powerpc/include/uapi/asm/Kbuild b/arch/powerpc/include/uapi/asm/Kbuild
index 1a6ed5919ffdb..a658091a19f90 100644
--- a/arch/powerpc/include/uapi/asm/Kbuild
+++ b/arch/powerpc/include/uapi/asm/Kbuild
@@ -7,3 +7,4 @@ generic-y += poll.h
generic-y += resource.h
generic-y += sockios.h
generic-y += statfs.h
+generic-y += siginfo.h
diff --git a/arch/powerpc/include/uapi/asm/siginfo.h b/arch/powerpc/include/uapi/asm/siginfo.h
deleted file mode 100644
index 1d51d9b882212..0000000000000
--- a/arch/powerpc/include/uapi/asm/siginfo.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
-#ifndef _ASM_POWERPC_SIGINFO_H
-#define _ASM_POWERPC_SIGINFO_H
-
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifdef __powerpc64__
-# define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
-#endif
-
-#include <asm-generic/siginfo.h>
-
-#endif /* _ASM_POWERPC_SIGINFO_H */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index bb6ac471a784e..5d983d8bac279 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -620,8 +620,6 @@ void do_send_trap(struct pt_regs *regs, unsigned long address,
void do_break (struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
- siginfo_t info;
-
current->thread.trap_nr = TRAP_HWBKPT;
if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
11, SIGSEGV) == NOTIFY_STOP)
@@ -634,12 +632,7 @@ void do_break (struct pt_regs *regs, unsigned long address,
hw_breakpoint_disable();
/* Deliver the signal to userspace */
- clear_siginfo(&info);
- info.si_signo = SIGTRAP;
- info.si_errno = 0;
- info.si_code = TRAP_HWBKPT;
- info.si_addr = (void __user *)address;
- force_sig_info(SIGTRAP, &info, current);
+ force_sig_fault(SIGTRAP, TRAP_HWBKPT, (void __user *)address, current);
}
#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index c85adb8582713..ab1bd06d7c448 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -307,12 +307,9 @@ void die(const char *str, struct pt_regs *regs, long err)
}
NOKPROBE_SYMBOL(die);
-void user_single_step_siginfo(struct task_struct *tsk,
- struct pt_regs *regs, siginfo_t *info)
+void user_single_step_report(struct pt_regs *regs)
{
- info->si_signo = SIGTRAP;
- info->si_code = TRAP_TRACE;
- info->si_addr = (void __user *)regs->nip;
+ force_sig_fault(SIGTRAP, TRAP_TRACE, (void __user *)regs->nip, current);
}
static void show_signal_msg(int signr, struct pt_regs *regs, int code,
@@ -341,14 +338,12 @@ static void show_signal_msg(int signr, struct pt_regs *regs, int code,
show_user_instructions(regs);
}
-void _exception_pkey(int signr, struct pt_regs *regs, int code,
- unsigned long addr, int key)
+static bool exception_common(int signr, struct pt_regs *regs, int code,
+ unsigned long addr)
{
- siginfo_t info;
-
if (!user_mode(regs)) {
die("Exception in kernel mode", regs, signr);
- return;
+ return false;
}
show_signal_msg(signr, regs, code, addr);
@@ -364,18 +359,23 @@ void _exception_pkey(int signr, struct pt_regs *regs, int code,
*/
thread_pkey_regs_save(&current->thread);
- clear_siginfo(&info);
- info.si_signo = signr;
- info.si_code = code;
- info.si_addr = (void __user *) addr;
- info.si_pkey = key;
+ return true;
+}
+
+void _exception_pkey(struct pt_regs *regs, unsigned long addr, int key)
+{
+ if (!exception_common(SIGSEGV, regs, SEGV_PKUERR, addr))
+ return;
- force_sig_info(signr, &info, current);
+ force_sig_pkuerr((void __user *) addr, key);
}
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
{
- _exception_pkey(signr, regs, code, addr, 0);
+ if (!exception_common(signr, regs, code, addr))
+ return;
+
+ force_sig_fault(signr, code, (void __user *)addr, current);
}
void system_reset_exception(struct pt_regs *regs)
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index d51cf5f4e45ef..1697e903bbf28 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -103,8 +103,7 @@ static bool store_updates_sp(unsigned int inst)
*/
static int
-__bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code,
- int pkey)
+__bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code)
{
/*
* If we are in kernel mode, bail out with a SEGV, this will
@@ -114,18 +113,17 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code,
if (!user_mode(regs))
return SIGSEGV;
- _exception_pkey(SIGSEGV, regs, si_code, address, pkey);
+ _exception(SIGSEGV, regs, si_code, address);
return 0;
}
static noinline int bad_area_nosemaphore(struct pt_regs *regs, unsigned long address)
{
- return __bad_area_nosemaphore(regs, address, SEGV_MAPERR, 0);
+ return __bad_area_nosemaphore(regs, address, SEGV_MAPERR);
}
-static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code,
- int pkey)
+static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code)
{
struct mm_struct *mm = current->mm;
@@ -135,54 +133,61 @@ static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code,
*/
up_read(&mm->mmap_sem);
- return __bad_area_nosemaphore(regs, address, si_code, pkey);
+ return __bad_area_nosemaphore(regs, address, si_code);
}
static noinline int bad_area(struct pt_regs *regs, unsigned long address)
{
- return __bad_area(regs, address, SEGV_MAPERR, 0);
+ return __bad_area(regs, address, SEGV_MAPERR);
}
static int bad_key_fault_exception(struct pt_regs *regs, unsigned long address,
int pkey)
{
- return __bad_area_nosemaphore(regs, address, SEGV_PKUERR, pkey);
+ /*
+ * If we are in kernel mode, bail out with a SEGV, this will
+ * be caught by the assembly which will restore the non-volatile
+ * registers before calling bad_page_fault()
+ */
+ if (!user_mode(regs))
+ return SIGSEGV;
+
+ _exception_pkey(regs, address, pkey);
+
+ return 0;
}
static noinline int bad_access(struct pt_regs *regs, unsigned long address)
{
- return __bad_area(regs, address, SEGV_ACCERR, 0);
+ return __bad_area(regs, address, SEGV_ACCERR);
}
static int do_sigbus(struct pt_regs *regs, unsigned long address,
vm_fault_t fault)
{
- siginfo_t info;
- unsigned int lsb = 0;
-
if (!user_mode(regs))
return SIGBUS;
current->thread.trap_nr = BUS_ADRERR;
- clear_siginfo(&info);
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_ADRERR;
- info.si_addr = (void __user *)address;
#ifdef CONFIG_MEMORY_FAILURE
if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
+ unsigned int lsb = 0; /* shutup gcc */
+
pr_err("MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",
current->comm, current->pid, address);
- info.si_code = BUS_MCEERR_AR;
+
+ if (fault & VM_FAULT_HWPOISON_LARGE)
+ lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
+ if (fault & VM_FAULT_HWPOISON)
+ lsb = PAGE_SHIFT;
+
+ force_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb,
+ current);
+ return 0;
}
- if (fault & VM_FAULT_HWPOISON_LARGE)
- lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
- if (fault & VM_FAULT_HWPOISON)
- lsb = PAGE_SHIFT;
#endif
- info.si_addr_lsb = lsb;
- force_sig_info(SIGBUS, &info, current);
+ force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, current);
return 0;
}
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 0c45cdbac4cfc..7f12c7b78c0f6 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -50,11 +50,11 @@ struct cbe_spu_info cbe_spu_info[MAX_NUMNODES];
EXPORT_SYMBOL_GPL(cbe_spu_info);
/*
- * The spufs fault-handling code needs to call force_sig_info to raise signals
+ * The spufs fault-handling code needs to call force_sig_fault to raise signals
* on DMA errors. Export it here to avoid general kernel-wide access to this
* function
*/
-EXPORT_SYMBOL_GPL(force_sig_info);
+EXPORT_SYMBOL_GPL(force_sig_fault);
/*
* Protects cbe_spu_info and spu->number.
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
index 83cf58daaa797..971ac43b5d60b 100644
--- a/arch/powerpc/platforms/cell/spufs/fault.c
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -36,42 +36,32 @@
static void spufs_handle_event(struct spu_context *ctx,
unsigned long ea, int type)
{
- siginfo_t info;
-
if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
ctx->event_return |= type;
wake_up_all(&ctx->stop_wq);
return;
}
- clear_siginfo(&info);
-
switch (type) {
case SPE_EVENT_INVALID_DMA:
- info.si_signo = SIGBUS;
- info.si_code = BUS_OBJERR;
+ force_sig_fault(SIGBUS, BUS_OBJERR, NULL, current);
break;
case SPE_EVENT_SPE_DATA_STORAGE:
- info.si_signo = SIGSEGV;
- info.si_addr = (void __user *)ea;
- info.si_code = SEGV_ACCERR;
ctx->ops->restart_dma(ctx);
+ force_sig_fault(SIGSEGV, SEGV_ACCERR, (void __user *)ea,
+ current);
break;
case SPE_EVENT_DMA_ALIGNMENT:
- info.si_signo = SIGBUS;
/* DAR isn't set for an alignment fault :( */
- info.si_code = BUS_ADRALN;
+ force_sig_fault(SIGBUS, BUS_ADRALN, NULL, current);
break;
case SPE_EVENT_SPE_ERROR:
- info.si_signo = SIGILL;
- info.si_addr = (void __user *)(unsigned long)
- ctx->ops->npc_read(ctx) - 4;
- info.si_code = ILL_ILLOPC;
+ force_sig_fault(
+ SIGILL, ILL_ILLOPC,
+ (void __user *)(unsigned long)
+ ctx->ops->npc_read(ctx) - 4, current);
break;
}
-
- if (info.si_signo)
- force_sig_info(info.si_signo, &info, current);
}
int spufs_handle_class0(struct spu_context *ctx)
diff --git a/arch/riscv/include/uapi/asm/Kbuild b/arch/riscv/include/uapi/asm/Kbuild
index 7e91f48504757..5511b99181316 100644
--- a/arch/riscv/include/uapi/asm/Kbuild
+++ b/arch/riscv/include/uapi/asm/Kbuild
@@ -26,3 +26,4 @@ generic-y += swab.h
generic-y += termbits.h
generic-y += termios.h
generic-y += types.h
+generic-y += siginfo.h
diff --git a/arch/riscv/include/uapi/asm/siginfo.h b/arch/riscv/include/uapi/asm/siginfo.h
deleted file mode 100644
index f96849aac662c..0000000000000
--- a/arch/riscv/include/uapi/asm/siginfo.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2012 ARM Ltd.
- * Copyright (C) 2016 SiFive, Inc.
- *
- * 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 (__SIZEOF_POINTER__ == 4 ? 12 : 16)
-
-#include <asm-generic/siginfo.h>
-
-#endif
diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild
index e364873e0d109..dc38a90cf0912 100644
--- a/arch/s390/include/uapi/asm/Kbuild
+++ b/arch/s390/include/uapi/asm/Kbuild
@@ -18,3 +18,4 @@ generic-y += shmbuf.h
generic-y += sockios.h
generic-y += swab.h
generic-y += termbits.h
+generic-y += siginfo.h \ No newline at end of file
diff --git a/arch/s390/include/uapi/asm/siginfo.h b/arch/s390/include/uapi/asm/siginfo.h
deleted file mode 100644
index 6984820f2f1c3..0000000000000
--- a/arch/s390/include/uapi/asm/siginfo.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * S390 version
- *
- * Derived from "include/asm-i386/siginfo.h"
- */
-
-#ifndef _S390_SIGINFO_H
-#define _S390_SIGINFO_H
-
-#ifdef __s390x__
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
-#endif
-
-#include <asm-generic/siginfo.h>
-
-#endif
diff --git a/arch/sparc/include/uapi/asm/siginfo.h b/arch/sparc/include/uapi/asm/siginfo.h
index e7049550ac823..68bdde4c2a2ec 100644
--- a/arch/sparc/include/uapi/asm/siginfo.h
+++ b/arch/sparc/include/uapi/asm/siginfo.h
@@ -4,7 +4,6 @@
#if defined(__sparc__) && defined(__arch64__)
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
#define __ARCH_SI_BAND_T int
#endif /* defined(__sparc__) && defined(__arch64__) */
@@ -17,10 +16,4 @@
#define SI_NOINFO 32767 /* no information in siginfo_t */
-/*
- * SIGEMT si_codes
- */
-#define EMT_TAGOVF 1 /* tag overflow */
-#define NSIGEMT 1
-
#endif /* _UAPI__SPARC_SIGINFO_H */
diff --git a/arch/unicore32/include/asm/bug.h b/arch/unicore32/include/asm/bug.h
index 93a56f3e23440..83c7687a0e613 100644
--- a/arch/unicore32/include/asm/bug.h
+++ b/arch/unicore32/include/asm/bug.h
@@ -17,6 +17,7 @@ struct siginfo;
extern void die(const char *msg, struct pt_regs *regs, int err);
extern void uc32_notify_die(const char *str, struct pt_regs *regs,
- struct siginfo *info, unsigned long err, unsigned long trap);
+ int sig, int code, void __user *addr,
+ unsigned long err, unsigned long trap);
#endif /* __UNICORE_BUG_H__ */
diff --git a/arch/unicore32/kernel/fpu-ucf64.c b/arch/unicore32/kernel/fpu-ucf64.c
index 8594b168f25e8..fc5dad32a9825 100644
--- a/arch/unicore32/kernel/fpu-ucf64.c
+++ b/arch/unicore32/kernel/fpu-ucf64.c
@@ -54,14 +54,6 @@
*/
void ucf64_raise_sigfpe(struct pt_regs *regs)
{
- siginfo_t info;
-
- clear_siginfo(&info);
-
- info.si_signo = SIGFPE;
- info.si_code = FPE_FLTUNK;
- info.si_addr = (void __user *)(instruction_pointer(regs) - 4);
-
/*
* This is the same as NWFPE, because it's not clear what
* this is used for
@@ -69,7 +61,9 @@ void ucf64_raise_sigfpe(struct pt_regs *regs)
current->thread.error_code = 0;
current->thread.trap_no = 6;
- send_sig_info(SIGFPE, &info, current);
+ send_sig_fault(SIGFPE, FPE_FLTUNK,
+ (void __user *)(instruction_pointer(regs) - 4),
+ current);
}
/*
diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c
index c4ac6043ebb0f..fb376d83e0439 100644
--- a/arch/unicore32/kernel/traps.c
+++ b/arch/unicore32/kernel/traps.c
@@ -241,13 +241,14 @@ void die(const char *str, struct pt_regs *regs, int err)
}
void uc32_notify_die(const char *str, struct pt_regs *regs,
- struct siginfo *info, unsigned long err, unsigned long trap)
+ int sig, int code, void __user *addr,
+ unsigned long err, unsigned long trap)
{
if (user_mode(regs)) {
current->thread.error_code = err;
current->thread.trap_no = trap;
- force_sig_info(info->si_signo, info, current);
+ force_sig_fault(sig, code, addr, current);
} else
die(str, regs, err);
}
diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c
index 8f12a5b50a42b..b9a3a50644c10 100644
--- a/arch/unicore32/mm/fault.c
+++ b/arch/unicore32/mm/fault.c
@@ -120,17 +120,10 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
unsigned int fsr, unsigned int sig, int code,
struct pt_regs *regs)
{
- struct siginfo si;
-
tsk->thread.address = addr;
tsk->thread.error_code = fsr;
tsk->thread.trap_no = 14;
- clear_siginfo(&si);
- si.si_signo = sig;
- si.si_errno = 0;
- si.si_code = code;
- si.si_addr = (void __user *)addr;
- force_sig_info(sig, &si, tsk);
+ force_sig_fault(sig, code, (void __user *)addr, tsk);
}
void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
@@ -466,7 +459,6 @@ asmlinkage void do_DataAbort(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
- struct siginfo info;
if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
return;
@@ -474,19 +466,14 @@ asmlinkage void do_DataAbort(unsigned long addr, unsigned int fsr,
printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
inf->name, fsr, addr);
- clear_siginfo(&info);
- info.si_signo = inf->sig;
- info.si_errno = 0;
- info.si_code = inf->code;
- info.si_addr = (void __user *)addr;
- uc32_notify_die("", regs, &info, fsr, 0);
+ uc32_notify_die("", regs, inf->sig, inf->code, (void __user *)addr,
+ fsr, 0);
}
asmlinkage void do_PrefetchAbort(unsigned long addr,
unsigned int ifsr, struct pt_regs *regs)
{
const struct fsr_info *inf = fsr_info + fsr_fs(ifsr);
- struct siginfo info;
if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
return;
@@ -494,10 +481,6 @@ asmlinkage void do_PrefetchAbort(unsigned long addr,
printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
inf->name, ifsr, addr);
- clear_siginfo(&info);
- info.si_signo = inf->sig;
- info.si_errno = 0;
- info.si_code = inf->code;
- info.si_addr = (void __user *)addr;
- uc32_notify_die("", regs, &info, ifsr, 0);
+ uc32_notify_die("", regs, inf->sig, inf->code, (void __user *)addr,
+ ifsr, 0);
}
diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c
index 82ed001e8909d..85fd85d52ffde 100644
--- a/arch/x86/entry/vsyscall/vsyscall_64.c
+++ b/arch/x86/entry/vsyscall/vsyscall_64.c
@@ -100,20 +100,13 @@ static bool write_ok_or_segv(unsigned long ptr, size_t size)
*/
if (!access_ok(VERIFY_WRITE, (void __user *)ptr, size)) {
- siginfo_t info;
struct thread_struct *thread = &current->thread;
thread->error_code = 6; /* user fault, no page, write */
thread->cr2 = ptr;
thread->trap_nr = X86_TRAP_PF;
- clear_siginfo(&info);
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_code = SEGV_MAPERR;
- info.si_addr = (void __user *)ptr;
-
- force_sig_info(SIGSEGV, &info, current);
+ force_sig_fault(SIGSEGV, SEGV_MAPERR, (void __user *)ptr, current);
return false;
} else {
return true;
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index fb97cf7c41371..a0f46bdd9f242 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -240,6 +240,6 @@ static inline bool in_compat_syscall(void)
struct compat_siginfo;
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
- const siginfo_t *from, bool x32_ABI);
+ const kernel_siginfo_t *from, bool x32_ABI);
#endif /* _ASM_X86_COMPAT_H */
diff --git a/arch/x86/include/asm/mpx.h b/arch/x86/include/asm/mpx.h
index 61eb4b63c5ec0..d0b1434fb0b69 100644
--- a/arch/x86/include/asm/mpx.h
+++ b/arch/x86/include/asm/mpx.h
@@ -57,8 +57,14 @@
#define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1))
#define MPX_BNDSTA_ERROR_CODE 0x3
+struct mpx_fault_info {
+ void __user *addr;
+ void __user *lower;
+ void __user *upper;
+};
+
#ifdef CONFIG_X86_INTEL_MPX
-siginfo_t *mpx_generate_siginfo(struct pt_regs *regs);
+int mpx_fault_info(struct mpx_fault_info *info, struct pt_regs *regs);
int mpx_handle_bd_fault(void);
static inline int kernel_managing_mpx_tables(struct mm_struct *mm)
{
@@ -78,9 +84,9 @@ void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long mpx_unmapped_area_check(unsigned long addr, unsigned long len,
unsigned long flags);
#else
-static inline siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
+static inline int mpx_fault_info(struct mpx_fault_info *info, struct pt_regs *regs)
{
- return NULL;
+ return -EINVAL;
}
static inline int mpx_handle_bd_fault(void)
{
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index f236bcd5485d3..143c99499531c 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -293,7 +293,7 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
#define arch_has_block_step() (boot_cpu_data.x86 >= 6)
#endif
-#define ARCH_HAS_USER_SINGLE_STEP_INFO
+#define ARCH_HAS_USER_SINGLE_STEP_REPORT
/*
* When hitting ptrace_stop(), we cannot return using SYSRET because
diff --git a/arch/x86/include/asm/trace/mpx.h b/arch/x86/include/asm/trace/mpx.h
index 7bd92db09e8da..54133017267c3 100644
--- a/arch/x86/include/asm/trace/mpx.h
+++ b/arch/x86/include/asm/trace/mpx.h
@@ -11,12 +11,12 @@
TRACE_EVENT(mpx_bounds_register_exception,
- TP_PROTO(void *addr_referenced,
+ TP_PROTO(void __user *addr_referenced,
const struct mpx_bndreg *bndreg),
TP_ARGS(addr_referenced, bndreg),
TP_STRUCT__entry(
- __field(void *, addr_referenced)
+ __field(void __user *, addr_referenced)
__field(u64, lower_bound)
__field(u64, upper_bound)
),
diff --git a/arch/x86/include/uapi/asm/siginfo.h b/arch/x86/include/uapi/asm/siginfo.h
index b3d1579571779..6642d8be40c4e 100644
--- a/arch/x86/include/uapi/asm/siginfo.h
+++ b/arch/x86/include/uapi/asm/siginfo.h
@@ -7,8 +7,6 @@
typedef long long __kernel_si_clock_t __attribute__((aligned(4)));
# define __ARCH_SI_CLOCK_T __kernel_si_clock_t
# define __ARCH_SI_ATTRIBUTES __attribute__((aligned(8)))
-# else /* x86-64 */
-# define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
# endif
#endif
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index d8f49c7384a32..ffae9b9740fdf 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1359,33 +1359,18 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
#endif
}
-static void fill_sigtrap_info(struct task_struct *tsk,
- struct pt_regs *regs,
- int error_code, int si_code,
- struct siginfo *info)
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+ int error_code, int si_code)
{
tsk->thread.trap_nr = X86_TRAP_DB;
tsk->thread.error_code = error_code;
- info->si_signo = SIGTRAP;
- info->si_code = si_code;
- info->si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL;
-}
-
-void user_single_step_siginfo(struct task_struct *tsk,
- struct pt_regs *regs,
- struct siginfo *info)
-{
- fill_sigtrap_info(tsk, regs, 0, TRAP_BRKPT, info);
+ /* Send us the fake SIGTRAP */
+ force_sig_fault(SIGTRAP, si_code,
+ user_mode(regs) ? (void __user *)regs->ip : NULL, tsk);
}
-void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
- int error_code, int si_code)
+void user_single_step_report(struct pt_regs *regs)
{
- struct siginfo info;
-
- clear_siginfo(&info);
- fill_sigtrap_info(tsk, regs, error_code, si_code, &info);
- /* Send us the fake SIGTRAP */
- force_sig_info(SIGTRAP, &info, tsk);
+ send_sigtrap(current, regs, 0, TRAP_BRKPT);
}
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 5bd0a997d81e2..8f6dcd88202e8 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -189,7 +189,7 @@ int fixup_bug(struct pt_regs *regs, int trapnr)
}
static nokprobe_inline int
-do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
+do_trap_no_signal(struct task_struct *tsk, int trapnr, const char *str,
struct pt_regs *regs, long error_code)
{
if (v8086_mode(regs)) {
@@ -202,10 +202,7 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
error_code, trapnr))
return 0;
}
- return -1;
- }
-
- if (!user_mode(regs)) {
+ } else if (!user_mode(regs)) {
if (fixup_exception(regs, trapnr, error_code, 0))
return 0;
@@ -214,49 +211,6 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
die(str, regs, error_code);
}
- return -1;
-}
-
-static siginfo_t *fill_trap_info(struct pt_regs *regs, int signr, int trapnr,
- siginfo_t *info)
-{
- unsigned long siaddr;
- int sicode;
-
- switch (trapnr) {
- default:
- return SEND_SIG_PRIV;
-
- case X86_TRAP_DE:
- sicode = FPE_INTDIV;
- siaddr = uprobe_get_trap_addr(regs);
- break;
- case X86_TRAP_UD:
- sicode = ILL_ILLOPN;
- siaddr = uprobe_get_trap_addr(regs);
- break;
- case X86_TRAP_AC:
- sicode = BUS_ADRALN;
- siaddr = 0;
- break;
- }
-
- info->si_signo = signr;
- info->si_errno = 0;
- info->si_code = sicode;
- info->si_addr = (void __user *)siaddr;
- return info;
-}
-
-static void
-do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
- long error_code, siginfo_t *info)
-{
- struct task_struct *tsk = current;
-
-
- if (!do_trap_no_signal(tsk, trapnr, str, regs, error_code))
- return;
/*
* We want error_code and trap_nr set for userspace faults and
* kernelspace faults which result in die(), but not
@@ -269,24 +223,45 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = trapnr;
+ return -1;
+}
+
+static void show_signal(struct task_struct *tsk, int signr,
+ const char *type, const char *desc,
+ struct pt_regs *regs, long error_code)
+{
if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
printk_ratelimit()) {
- pr_info("%s[%d] trap %s ip:%lx sp:%lx error:%lx",
- tsk->comm, tsk->pid, str,
+ pr_info("%s[%d] %s%s ip:%lx sp:%lx error:%lx",
+ tsk->comm, task_pid_nr(tsk), type, desc,
regs->ip, regs->sp, error_code);
print_vma_addr(KERN_CONT " in ", regs->ip);
pr_cont("\n");
}
+}
+
+static void
+do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
+ long error_code, int sicode, void __user *addr)
+{
+ struct task_struct *tsk = current;
+
+
+ if (!do_trap_no_signal(tsk, trapnr, str, regs, error_code))
+ return;
+
+ show_signal(tsk, signr, "trap ", str, regs, error_code);
- force_sig_info(signr, info ?: SEND_SIG_PRIV, tsk);
+ if (!sicode)
+ force_sig(signr, tsk);
+ else
+ force_sig_fault(signr, sicode, addr, tsk);
}
NOKPROBE_SYMBOL(do_trap);
static void do_error_trap(struct pt_regs *regs, long error_code, char *str,
- unsigned long trapnr, int signr)
+ unsigned long trapnr, int signr, int sicode, void __user *addr)
{
- siginfo_t info;
-
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
/*
@@ -299,26 +274,26 @@ static void do_error_trap(struct pt_regs *regs, long error_code, char *str,
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) !=
NOTIFY_STOP) {
cond_local_irq_enable(regs);
- clear_siginfo(&info);
- do_trap(trapnr, signr, str, regs, error_code,
- fill_trap_info(regs, signr, trapnr, &info));
+ do_trap(trapnr, signr, str, regs, error_code, sicode, addr);
}
}
-#define DO_ERROR(trapnr, signr, str, name) \
-dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
-{ \
- do_error_trap(regs, error_code, str, trapnr, signr); \
+#define IP ((void __user *)uprobe_get_trap_addr(regs))
+#define DO_ERROR(trapnr, signr, sicode, addr, str, name) \
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
+{ \
+ do_error_trap(regs, error_code, str, trapnr, signr, sicode, addr); \
}
-DO_ERROR(X86_TRAP_DE, SIGFPE, "divide error", divide_error)
-DO_ERROR(X86_TRAP_OF, SIGSEGV, "overflow", overflow)
-DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op)
-DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun)
-DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present)
-DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment)
-DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check)
+DO_ERROR(X86_TRAP_DE, SIGFPE, FPE_INTDIV, IP, "divide error", divide_error)
+DO_ERROR(X86_TRAP_OF, SIGSEGV, 0, NULL, "overflow", overflow)
+DO_ERROR(X86_TRAP_UD, SIGILL, ILL_ILLOPN, IP, "invalid opcode", invalid_op)
+DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, 0, NULL, "coprocessor segment overrun", coprocessor_segment_overrun)
+DO_ERROR(X86_TRAP_TS, SIGSEGV, 0, NULL, "invalid TSS", invalid_TSS)
+DO_ERROR(X86_TRAP_NP, SIGBUS, 0, NULL, "segment not present", segment_not_present)
+DO_ERROR(X86_TRAP_SS, SIGBUS, 0, NULL, "stack segment", stack_segment)
+DO_ERROR(X86_TRAP_AC, SIGBUS, BUS_ADRALN, NULL, "alignment check", alignment_check)
+#undef IP
#ifdef CONFIG_VMAP_STACK
__visible void __noreturn handle_stack_overflow(const char *message,
@@ -459,7 +434,6 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
{
const struct mpx_bndcsr *bndcsr;
- siginfo_t *info;
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
if (notify_die(DIE_TRAP, "bounds", regs, error_code,
@@ -497,8 +471,11 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
goto exit_trap;
break; /* Success, it was handled */
case 1: /* Bound violation. */
- info = mpx_generate_siginfo(regs);
- if (IS_ERR(info)) {
+ {
+ struct task_struct *tsk = current;
+ struct mpx_fault_info mpx;
+
+ if (mpx_fault_info(&mpx, regs)) {
/*
* We failed to decode the MPX instruction. Act as if
* the exception was not caused by MPX.
@@ -507,14 +484,20 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
}
/*
* Success, we decoded the instruction and retrieved
- * an 'info' containing the address being accessed
+ * an 'mpx' containing the address being accessed
* which caused the exception. This information
* allows and application to possibly handle the
* #BR exception itself.
*/
- do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, info);
- kfree(info);
+ if (!do_trap_no_signal(tsk, X86_TRAP_BR, "bounds", regs,
+ error_code))
+ break;
+
+ show_signal(tsk, SIGSEGV, "trap ", "bounds", regs, error_code);
+
+ force_sig_bnderr(mpx.addr, mpx.lower, mpx.upper);
break;
+ }
case 0: /* No exception caused by Intel MPX operations. */
goto exit_trap;
default:
@@ -531,12 +514,13 @@ exit_trap:
* up here if the kernel has MPX turned off at compile
* time..
*/
- do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, NULL);
+ do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, 0, NULL);
}
dotraplinkage void
do_general_protection(struct pt_regs *regs, long error_code)
{
+ const char *desc = "general protection fault";
struct task_struct *tsk;
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
@@ -570,25 +554,18 @@ do_general_protection(struct pt_regs *regs, long error_code)
kprobe_fault_handler(regs, X86_TRAP_GP))
return;
- if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
+ if (notify_die(DIE_GPF, desc, regs, error_code,
X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP)
- die("general protection fault", regs, error_code);
+ die(desc, regs, error_code);
return;
}
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = X86_TRAP_GP;
- if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
- printk_ratelimit()) {
- pr_info("%s[%d] general protection ip:%lx sp:%lx error:%lx",
- tsk->comm, task_pid_nr(tsk),
- regs->ip, regs->sp, error_code);
- print_vma_addr(KERN_CONT " in ", regs->ip);
- pr_cont("\n");
- }
+ show_signal(tsk, SIGSEGV, "", desc, regs, error_code);
- force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk);
+ force_sig(SIGSEGV, tsk);
}
NOKPROBE_SYMBOL(do_general_protection);
@@ -631,7 +608,7 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
goto exit;
cond_local_irq_enable(regs);
- do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
+ do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, 0, NULL);
cond_local_irq_disable(regs);
exit:
@@ -845,7 +822,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
{
struct task_struct *task = current;
struct fpu *fpu = &task->thread.fpu;
- siginfo_t info;
+ int si_code;
char *str = (trapnr == X86_TRAP_MF) ? "fpu exception" :
"simd exception";
@@ -871,18 +848,14 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
task->thread.trap_nr = trapnr;
task->thread.error_code = error_code;
- clear_siginfo(&info);
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_addr = (void __user *)uprobe_get_trap_addr(regs);
-
- info.si_code = fpu__exception_code(fpu, trapnr);
+ si_code = fpu__exception_code(fpu, trapnr);
/* Retry when we get spurious exceptions: */
- if (!info.si_code)
+ if (!si_code)
return;
- force_sig_info(SIGFPE, &info, task);
+ force_sig_fault(SIGFPE, si_code,
+ (void __user *)uprobe_get_trap_addr(regs), task);
}
dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
@@ -942,20 +915,13 @@ NOKPROBE_SYMBOL(do_device_not_available);
#ifdef CONFIG_X86_32
dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
{
- siginfo_t info;
-
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
local_irq_enable();
- clear_siginfo(&info);
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = ILL_BADSTK;
- info.si_addr = NULL;
if (notify_die(DIE_TRAP, "iret exception", regs, error_code,
X86_TRAP_IRET, SIGILL) != NOTIFY_STOP) {
do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
- &info);
+ ILL_BADSTK, (void __user *)NULL);
}
}
#endif
diff --git a/arch/x86/kernel/umip.c b/arch/x86/kernel/umip.c
index ff20b35e98ddd..f8f3cfda01ae0 100644
--- a/arch/x86/kernel/umip.c
+++ b/arch/x86/kernel/umip.c
@@ -271,19 +271,13 @@ static int emulate_umip_insn(struct insn *insn, int umip_inst,
*/
static void force_sig_info_umip_fault(void __user *addr, struct pt_regs *regs)
{
- siginfo_t info;
struct task_struct *tsk = current;
tsk->thread.cr2 = (unsigned long)addr;
tsk->thread.error_code = X86_PF_USER | X86_PF_WRITE;
tsk->thread.trap_nr = X86_TRAP_PF;
- clear_siginfo(&info);
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_code = SEGV_MAPERR;
- info.si_addr = addr;
- force_sig_info(SIGSEGV, &info, tsk);
+ force_sig_fault(SIGSEGV, SEGV_MAPERR, addr, tsk);
if (!(show_unhandled_signals && unhandled_signal(tsk, SIGSEGV)))
return;
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index deb576b23b7cf..843feb94a9501 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -1086,7 +1086,7 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs
pr_err("return address clobbered: pid=%d, %%sp=%#lx, %%ip=%#lx\n",
current->pid, regs->sp, regs->ip);
- force_sig_info(SIGSEGV, SEND_SIG_FORCED, current);
+ force_sig(SIGSEGV, current);
}
return -1;
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 51b953ad9d4ef..e843ec46609d3 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3125,16 +3125,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, int write, int map_writable,
static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *tsk)
{
- siginfo_t info;
-
- clear_siginfo(&info);
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_MCEERR_AR;
- info.si_addr = (void __user *)address;
- info.si_addr_lsb = PAGE_SHIFT;
-
- send_sig_info(SIGBUS, &info, tsk);
+ send_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, PAGE_SHIFT, tsk);
}
static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 2b1519bc5381b..b24eb4eb99849 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -157,79 +157,6 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
return prefetch;
}
-/*
- * A protection key fault means that the PKRU value did not allow
- * access to some PTE. Userspace can figure out what PKRU was
- * from the XSAVE state, and this function fills out a field in
- * siginfo so userspace can discover which protection key was set
- * on the PTE.
- *
- * If we get here, we know that the hardware signaled a X86_PF_PK
- * fault and that there was a VMA once we got in the fault
- * handler. It does *not* guarantee that the VMA we find here
- * was the one that we faulted on.
- *
- * 1. T1 : mprotect_key(foo, PAGE_SIZE, pkey=4);
- * 2. T1 : set PKRU to deny access to pkey=4, touches page
- * 3. T1 : faults...
- * 4. T2: mprotect_key(foo, PAGE_SIZE, pkey=5);
- * 5. T1 : enters fault handler, takes mmap_sem, etc...
- * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really
- * faulted on a pte with its pkey=4.
- */
-static void fill_sig_info_pkey(int si_signo, int si_code, siginfo_t *info,
- u32 *pkey)
-{
- /* This is effectively an #ifdef */
- if (!boot_cpu_has(X86_FEATURE_OSPKE))
- return;
-
- /* Fault not from Protection Keys: nothing to do */
- if ((si_code != SEGV_PKUERR) || (si_signo != SIGSEGV))
- return;
- /*
- * force_sig_info_fault() is called from a number of
- * contexts, some of which have a VMA and some of which
- * do not. The X86_PF_PK handing happens after we have a
- * valid VMA, so we should never reach this without a
- * valid VMA.
- */
- if (!pkey) {
- WARN_ONCE(1, "PKU fault with no VMA passed in");
- info->si_pkey = 0;
- return;
- }
- /*
- * si_pkey should be thought of as a strong hint, but not
- * absolutely guranteed to be 100% accurate because of
- * the race explained above.
- */
- info->si_pkey = *pkey;
-}
-
-static void
-force_sig_info_fault(int si_signo, int si_code, unsigned long address,
- struct task_struct *tsk, u32 *pkey, int fault)
-{
- unsigned lsb = 0;
- siginfo_t info;
-
- clear_siginfo(&info);
- info.si_signo = si_signo;
- info.si_errno = 0;
- info.si_code = si_code;
- info.si_addr = (void __user *)address;
- if (fault & VM_FAULT_HWPOISON_LARGE)
- lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
- if (fault & VM_FAULT_HWPOISON)
- lsb = PAGE_SHIFT;
- info.si_addr_lsb = lsb;
-
- fill_sig_info_pkey(si_signo, si_code, &info, pkey);
-
- force_sig_info(si_signo, &info, tsk);
-}
-
DEFINE_SPINLOCK(pgd_lock);
LIST_HEAD(pgd_list);
@@ -734,8 +661,8 @@ no_context(struct pt_regs *regs, unsigned long error_code,
tsk->thread.cr2 = address;
/* XXX: hwpoison faults will set the wrong code. */
- force_sig_info_fault(signal, si_code, address,
- tsk, NULL, 0);
+ force_sig_fault(signal, si_code, (void __user *)address,
+ tsk);
}
/*
@@ -862,7 +789,7 @@ static bool is_vsyscall_vaddr(unsigned long vaddr)
static void
__bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
- unsigned long address, u32 *pkey, int si_code)
+ unsigned long address, u32 pkey, int si_code)
{
struct task_struct *tsk = current;
@@ -898,7 +825,10 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = X86_TRAP_PF;
- force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey, 0);
+ if (si_code == SEGV_PKUERR)
+ force_sig_pkuerr((void __user *)address, pkey);
+
+ force_sig_fault(SIGSEGV, si_code, (void __user *)address, tsk);
return;
}
@@ -911,35 +841,29 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
static noinline void
bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
- unsigned long address, u32 *pkey)
+ unsigned long address)
{
- __bad_area_nosemaphore(regs, error_code, address, pkey, SEGV_MAPERR);
+ __bad_area_nosemaphore(regs, error_code, address, 0, SEGV_MAPERR);
}
static void
__bad_area(struct pt_regs *regs, unsigned long error_code,
- unsigned long address, struct vm_area_struct *vma, int si_code)
+ unsigned long address, u32 pkey, int si_code)
{
struct mm_struct *mm = current->mm;
- u32 pkey;
-
- if (vma)
- pkey = vma_pkey(vma);
-
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
up_read(&mm->mmap_sem);
- __bad_area_nosemaphore(regs, error_code, address,
- (vma) ? &pkey : NULL, si_code);
+ __bad_area_nosemaphore(regs, error_code, address, pkey, si_code);
}
static noinline void
bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address)
{
- __bad_area(regs, error_code, address, NULL, SEGV_MAPERR);
+ __bad_area(regs, error_code, address, 0, SEGV_MAPERR);
}
static inline bool bad_area_access_from_pkeys(unsigned long error_code,
@@ -968,18 +892,40 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
* But, doing it this way allows compiler optimizations
* if pkeys are compiled out.
*/
- if (bad_area_access_from_pkeys(error_code, vma))
- __bad_area(regs, error_code, address, vma, SEGV_PKUERR);
- else
- __bad_area(regs, error_code, address, vma, SEGV_ACCERR);
+ if (bad_area_access_from_pkeys(error_code, vma)) {
+ /*
+ * A protection key fault means that the PKRU value did not allow
+ * access to some PTE. Userspace can figure out what PKRU was
+ * from the XSAVE state. This function captures the pkey from
+ * the vma and passes it to userspace so userspace can discover
+ * which protection key was set on the PTE.
+ *
+ * If we get here, we know that the hardware signaled a X86_PF_PK
+ * fault and that there was a VMA once we got in the fault
+ * handler. It does *not* guarantee that the VMA we find here
+ * was the one that we faulted on.
+ *
+ * 1. T1 : mprotect_key(foo, PAGE_SIZE, pkey=4);
+ * 2. T1 : set PKRU to deny access to pkey=4, touches page
+ * 3. T1 : faults...
+ * 4. T2: mprotect_key(foo, PAGE_SIZE, pkey=5);
+ * 5. T1 : enters fault handler, takes mmap_sem, etc...
+ * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really
+ * faulted on a pte with its pkey=4.
+ */
+ u32 pkey = vma_pkey(vma);
+
+ __bad_area(regs, error_code, address, pkey, SEGV_PKUERR);
+ } else {
+ __bad_area(regs, error_code, address, 0, SEGV_ACCERR);
+ }
}
static void
do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
- u32 *pkey, unsigned int fault)
+ unsigned int fault)
{
struct task_struct *tsk = current;
- int code = BUS_ADRERR;
/* Kernel mode? Handle exceptions or die: */
if (!(error_code & X86_PF_USER)) {
@@ -997,18 +943,25 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
#ifdef CONFIG_MEMORY_FAILURE
if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
- printk(KERN_ERR
+ unsigned lsb = 0;
+
+ pr_err(
"MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",
tsk->comm, tsk->pid, address);
- code = BUS_MCEERR_AR;
+ if (fault & VM_FAULT_HWPOISON_LARGE)
+ lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
+ if (fault & VM_FAULT_HWPOISON)
+ lsb = PAGE_SHIFT;
+ force_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, tsk);
+ return;
}
#endif
- force_sig_info_fault(SIGBUS, code, address, tsk, pkey, fault);
+ force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, tsk);
}
static noinline void
mm_fault_error(struct pt_regs *regs, unsigned long error_code,
- unsigned long address, u32 *pkey, vm_fault_t fault)
+ unsigned long address, vm_fault_t fault)
{
if (fatal_signal_pending(current) && !(error_code & X86_PF_USER)) {
no_context(regs, error_code, address, 0, 0);
@@ -1032,9 +985,9 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
} else {
if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
VM_FAULT_HWPOISON_LARGE))
- do_sigbus(regs, error_code, address, pkey, fault);
+ do_sigbus(regs, error_code, address, fault);
else if (fault & VM_FAULT_SIGSEGV)
- bad_area_nosemaphore(regs, error_code, address, pkey);
+ bad_area_nosemaphore(regs, error_code, address);
else
BUG();
}
@@ -1267,7 +1220,7 @@ do_kern_addr_fault(struct pt_regs *regs, unsigned long hw_error_code,
* Don't take the mm semaphore here. If we fixup a prefetch
* fault we could otherwise deadlock:
*/
- bad_area_nosemaphore(regs, hw_error_code, address, NULL);
+ bad_area_nosemaphore(regs, hw_error_code, address);
}
NOKPROBE_SYMBOL(do_kern_addr_fault);
@@ -1283,7 +1236,6 @@ void do_user_addr_fault(struct pt_regs *regs,
struct mm_struct *mm;
vm_fault_t fault, major = 0;
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
- u32 pkey;
tsk = current;
mm = tsk->mm;
@@ -1304,7 +1256,7 @@ void do_user_addr_fault(struct pt_regs *regs,
* pages in the user address space.
*/
if (unlikely(smap_violation(hw_error_code, regs))) {
- bad_area_nosemaphore(regs, hw_error_code, address, NULL);
+ bad_area_nosemaphore(regs, hw_error_code, address);
return;
}
@@ -1313,7 +1265,7 @@ void do_user_addr_fault(struct pt_regs *regs,
* in a region with pagefaults disabled then we must not take the fault
*/
if (unlikely(faulthandler_disabled() || !mm)) {
- bad_area_nosemaphore(regs, hw_error_code, address, NULL);
+ bad_area_nosemaphore(regs, hw_error_code, address);
return;
}
@@ -1403,7 +1355,7 @@ void do_user_addr_fault(struct pt_regs *regs,
* Fault from code in kernel from
* which we do not expect faults.
*/
- bad_area_nosemaphore(regs, sw_error_code, address, NULL);
+ bad_area_nosemaphore(regs, sw_error_code, address);
return;
}
retry:
@@ -1467,10 +1419,7 @@ good_area:
* (potentially after handling any pending signal during the return to
* userland). The return to userland is identified whenever
* FAULT_FLAG_USER|FAULT_FLAG_KILLABLE are both set in flags.
- * Thus we have to be careful about not touching vma after handling the
- * fault, so we read the pkey beforehand.
*/
- pkey = vma_pkey(vma);
fault = handle_mm_fault(vma, address, flags);
major |= fault & VM_FAULT_MAJOR;
@@ -1499,7 +1448,7 @@ good_area:
up_read(&mm->mmap_sem);
if (unlikely(fault & VM_FAULT_ERROR)) {
- mm_fault_error(regs, sw_error_code, address, &pkey, fault);
+ mm_fault_error(regs, sw_error_code, address, fault);
return;
}
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
index e500949bae245..2385538e80656 100644
--- a/arch/x86/mm/mpx.c
+++ b/arch/x86/mm/mpx.c
@@ -118,14 +118,11 @@ bad_opcode:
* anything it wants in to the instructions. We can not
* trust anything about it. They might not be valid
* instructions or might encode invalid registers, etc...
- *
- * The caller is expected to kfree() the returned siginfo_t.
*/
-siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
+int mpx_fault_info(struct mpx_fault_info *info, struct pt_regs *regs)
{
const struct mpx_bndreg_state *bndregs;
const struct mpx_bndreg *bndreg;
- siginfo_t *info = NULL;
struct insn insn;
uint8_t bndregno;
int err;
@@ -153,11 +150,6 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
/* now go select the individual register in the set of 4 */
bndreg = &bndregs->bndreg[bndregno];
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
- err = -ENOMEM;
- goto err_out;
- }
/*
* The registers are always 64-bit, but the upper 32
* bits are ignored in 32-bit mode. Also, note that the
@@ -168,27 +160,23 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
* complains when casting from integers to different-size
* pointers.
*/
- info->si_lower = (void __user *)(unsigned long)bndreg->lower_bound;
- info->si_upper = (void __user *)(unsigned long)~bndreg->upper_bound;
- info->si_addr_lsb = 0;
- info->si_signo = SIGSEGV;
- info->si_errno = 0;
- info->si_code = SEGV_BNDERR;
- info->si_addr = insn_get_addr_ref(&insn, regs);
+ info->lower = (void __user *)(unsigned long)bndreg->lower_bound;
+ info->upper = (void __user *)(unsigned long)~bndreg->upper_bound;
+ info->addr = insn_get_addr_ref(&insn, regs);
+
/*
* We were not able to extract an address from the instruction,
* probably because there was something invalid in it.
*/
- if (info->si_addr == (void __user *)-1) {
+ if (info->addr == (void __user *)-1) {
err = -EINVAL;
goto err_out;
}
- trace_mpx_bounds_register_exception(info->si_addr, bndreg);
- return info;
+ trace_mpx_bounds_register_exception(info->addr, bndreg);
+ return 0;
err_out:
/* info might be NULL, but kfree() handles that */
- kfree(info);
- return ERR_PTR(err);
+ return err;
}
static __user void *mpx_get_bounds_dir(void)
diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h
index 120738d6e58b2..77ed3967c5b00 100644
--- a/drivers/misc/genwqe/card_base.h
+++ b/drivers/misc/genwqe/card_base.h
@@ -408,7 +408,7 @@ struct genwqe_file {
struct file *filp;
struct fasync_struct *async_queue;
- struct task_struct *owner;
+ struct pid *opener;
struct list_head list; /* entry in list of open files */
spinlock_t map_lock; /* lock for dma_mappings */
diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c
index f453ab82f0d7b..8c1b63a4337be 100644
--- a/drivers/misc/genwqe/card_dev.c
+++ b/drivers/misc/genwqe/card_dev.c
@@ -52,7 +52,7 @@ static void genwqe_add_file(struct genwqe_dev *cd, struct genwqe_file *cfile)
{
unsigned long flags;
- cfile->owner = current;
+ cfile->opener = get_pid(task_tgid(current));
spin_lock_irqsave(&cd->file_lock, flags);
list_add(&cfile->list, &cd->file_list);
spin_unlock_irqrestore(&cd->file_lock, flags);
@@ -65,6 +65,7 @@ static int genwqe_del_file(struct genwqe_dev *cd, struct genwqe_file *cfile)
spin_lock_irqsave(&cd->file_lock, flags);
list_del(&cfile->list);
spin_unlock_irqrestore(&cd->file_lock, flags);
+ put_pid(cfile->opener);
return 0;
}
@@ -275,7 +276,7 @@ static int genwqe_kill_fasync(struct genwqe_dev *cd, int sig)
return files;
}
-static int genwqe_force_sig(struct genwqe_dev *cd, int sig)
+static int genwqe_terminate(struct genwqe_dev *cd)
{
unsigned int files = 0;
unsigned long flags;
@@ -283,7 +284,7 @@ static int genwqe_force_sig(struct genwqe_dev *cd, int sig)
spin_lock_irqsave(&cd->file_lock, flags);
list_for_each_entry(cfile, &cd->file_list, list) {
- force_sig(sig, cfile->owner);
+ kill_pid(cfile->opener, SIGKILL, 1);
files++;
}
spin_unlock_irqrestore(&cd->file_lock, flags);
@@ -1352,7 +1353,7 @@ static int genwqe_inform_and_stop_processes(struct genwqe_dev *cd)
dev_warn(&pci_dev->dev,
"[%s] send SIGKILL and wait ...\n", __func__);
- rc = genwqe_force_sig(cd, SIGKILL); /* force terminate */
+ rc = genwqe_terminate(cd);
if (rc) {
/* Give kill_timout more seconds to end processes */
for (i = 0; (i < GENWQE_KILL_TIMEOUT) &&
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 06ed20dd01ba6..ad1ee5d01b535 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -348,7 +348,7 @@ static void send_sig_all(int sig)
if (is_global_init(p))
continue;
- do_send_sig_info(sig, SEND_SIG_FORCED, p, PIDTYPE_MAX);
+ do_send_sig_info(sig, SEND_SIG_PRIV, p, PIDTYPE_MAX);
}
read_unlock(&tasklist_lock);
}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 5e5da9acaf0a9..816d8ba971a26 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2743,7 +2743,7 @@ void __do_SAK(struct tty_struct *tty)
do_each_pid_task(session, PIDTYPE_SID, p) {
tty_notice(tty, "SAK: killed process %d (%s): by session\n",
task_pid_nr(p), p->comm);
- send_sig(SIGKILL, p, 1);
+ group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID);
} while_each_pid_task(session, PIDTYPE_SID, p);
/* Now kill any processes that happen to have the tty open */
@@ -2751,7 +2751,7 @@ void __do_SAK(struct tty_struct *tty)
if (p->signal->tty == tty) {
tty_notice(tty, "SAK: killed process %d (%s): by controlling tty\n",
task_pid_nr(p), p->comm);
- send_sig(SIGKILL, p, 1);
+ group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID);
continue;
}
task_lock(p);
@@ -2759,7 +2759,7 @@ void __do_SAK(struct tty_struct *tty)
if (i != 0) {
tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n",
task_pid_nr(p), p->comm, i - 1);
- force_sig(SIGKILL, p);
+ group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID);
}
task_unlock(p);
} while_each_thread(g, p);
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index ffccd40ea67da..a75bc0b8a50f0 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -582,7 +582,7 @@ static void async_completed(struct urb *urb)
{
struct async *as = urb->context;
struct usb_dev_state *ps = as->ps;
- struct siginfo sinfo;
+ struct kernel_siginfo sinfo;
struct pid *pid = NULL;
const struct cred *cred = NULL;
unsigned long flags;
@@ -2617,7 +2617,7 @@ const struct file_operations usbdev_file_operations = {
static void usbdev_remove(struct usb_device *udev)
{
struct usb_dev_state *ps;
- struct siginfo sinfo;
+ struct kernel_siginfo sinfo;
while (!list_empty(&udev->filelist)) {
ps = list_entry(udev->filelist.next, struct usb_dev_state, list);
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 1074cb82ec172..043f97ad8f226 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -405,7 +405,7 @@ static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
common->exception_req_tag = common->ep0_req_tag;
common->state = new_state;
if (common->thread_task)
- send_sig_info(SIGUSR1, SEND_SIG_FORCED,
+ send_sig_info(SIGUSR1, SEND_SIG_PRIV,
common->thread_task);
}
spin_unlock_irqrestore(&common->lock, flags);
@@ -2313,7 +2313,7 @@ static void handle_exception(struct fsg_common *common)
* into a high-priority EXIT exception.
*/
for (;;) {
- int sig = kernel_dequeue_signal(NULL);
+ int sig = kernel_dequeue_signal();
if (!sig)
break;
if (sig != SIGUSR1) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index efae2fb0930aa..54207327f98f8 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1580,7 +1580,7 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm)
}
static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
- const siginfo_t *siginfo)
+ const kernel_siginfo_t *siginfo)
{
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
@@ -1782,7 +1782,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
static int fill_note_info(struct elfhdr *elf, int phdrs,
struct elf_note_info *info,
- const siginfo_t *siginfo, struct pt_regs *regs)
+ const kernel_siginfo_t *siginfo, struct pt_regs *regs)
{
struct task_struct *dump_task = current;
const struct user_regset_view *view = task_user_regset_view(dump_task);
@@ -2031,7 +2031,7 @@ static int elf_note_info_init(struct elf_note_info *info)
static int fill_note_info(struct elfhdr *elf, int phdrs,
struct elf_note_info *info,
- const siginfo_t *siginfo, struct pt_regs *regs)
+ const kernel_siginfo_t *siginfo, struct pt_regs *regs)
{
struct list_head *t;
struct core_thread *ct;
diff --git a/fs/coredump.c b/fs/coredump.c
index 1e2c87acac9b0..e42e17e55bfd5 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -536,7 +536,7 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)
return err;
}
-void do_coredump(const siginfo_t *siginfo)
+void do_coredump(const kernel_siginfo_t *siginfo)
{
struct core_state core_state;
struct core_name cn;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 4137d96534a6c..083185174c6d1 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -735,7 +735,7 @@ static void send_sigio_to_task(struct task_struct *p,
return;
switch (signum) {
- siginfo_t si;
+ kernel_siginfo_t si;
default:
/* Queue a rt signal with the appropriate fd as its
value. We use SI_SIGIO as the source, not
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 453a6a1fff34e..2b4d5013dc5d0 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -125,7 +125,7 @@ static int jffs2_garbage_collect_thread(void *_c)
if (try_to_freeze())
goto again;
- signr = kernel_dequeue_signal(NULL);
+ signr = kernel_dequeue_signal();
switch(signr) {
case SIGSTOP:
diff --git a/fs/signalfd.c b/fs/signalfd.c
index 4fcd1498acf52..757afc7c5895b 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -79,7 +79,7 @@ static __poll_t signalfd_poll(struct file *file, poll_table *wait)
* Copied from copy_siginfo_to_user() in kernel/signal.c
*/
static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
- siginfo_t const *kinfo)
+ kernel_siginfo_t const *kinfo)
{
struct signalfd_siginfo new;
@@ -163,7 +163,7 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
return sizeof(*uinfo);
}
-static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info,
+static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info,
int nonblock)
{
ssize_t ret;
@@ -215,7 +215,7 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
struct signalfd_siginfo __user *siginfo;
int nonblock = file->f_flags & O_NONBLOCK;
ssize_t ret, total = 0;
- siginfo_t info;
+ kernel_siginfo_t info;
count /= sizeof(struct signalfd_siginfo);
if (!count)
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index c05f24fac4f62..e9f5fe69df312 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -78,7 +78,7 @@ struct linux_binprm {
/* Function parameter for binfmt->coredump */
struct coredump_params {
- const siginfo_t *siginfo;
+ const kernel_siginfo_t *siginfo;
struct pt_regs *regs;
struct file *file;
unsigned long limit;
diff --git a/include/linux/compat.h b/include/linux/compat.h
index de0c13bdcd2c7..e75b926bc5dfd 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -455,8 +455,8 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size);
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
unsigned long bitmap_size);
-int copy_siginfo_from_user32(siginfo_t *to, const struct compat_siginfo __user *from);
-int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from);
+int copy_siginfo_from_user32(kernel_siginfo_t *to, const struct compat_siginfo __user *from);
+int copy_siginfo_to_user32(struct compat_siginfo __user *to, const kernel_siginfo_t *from);
int get_compat_sigevent(struct sigevent *event,
const struct compat_sigevent __user *u_event);
diff --git a/include/linux/coredump.h b/include/linux/coredump.h
index 207aed96a5b7d..abf4b4e65dbb9 100644
--- a/include/linux/coredump.h
+++ b/include/linux/coredump.h
@@ -17,9 +17,9 @@ extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr);
extern int dump_align(struct coredump_params *cprm, int align);
extern void dump_truncate(struct coredump_params *cprm);
#ifdef CONFIG_COREDUMP
-extern void do_coredump(const siginfo_t *siginfo);
+extern void do_coredump(const kernel_siginfo_t *siginfo);
#else
-static inline void do_coredump(const siginfo_t *siginfo) {}
+static inline void do_coredump(const kernel_siginfo_t *siginfo) {}
#endif
#endif /* _LINUX_COREDUMP_H */
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 97a020c616ad1..bb40f6d34163b 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -672,7 +672,7 @@
* Return 0 if permission is granted.
* @task_kill:
* Check permission before sending signal @sig to @p. @info can be NULL,
- * the constant 1, or a pointer to a siginfo structure. If @info is 1 or
+ * the constant 1, or a pointer to a kernel_siginfo structure. If @info is 1 or
* SI_FROMKERNEL(info) is true, then the signal should be viewed as coming
* from the kernel and should typically be permitted.
* SIGIO signals are handled separately by the send_sigiotask hook in
@@ -1606,7 +1606,7 @@ union security_list_options {
int (*task_setscheduler)(struct task_struct *p);
int (*task_getscheduler)(struct task_struct *p);
int (*task_movememory)(struct task_struct *p);
- int (*task_kill)(struct task_struct *p, struct siginfo *info,
+ int (*task_kill)(struct task_struct *p, struct kernel_siginfo *info,
int sig, const struct cred *cred);
int (*task_prctl)(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index ee7e987ea1b43..e96581ca7c9d3 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -126,5 +126,5 @@ void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
-void posixtimer_rearm(struct siginfo *info);
+void posixtimer_rearm(struct kernel_siginfo *info);
#endif
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index e5e5ef513df30..6c2ffed907f5f 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -353,14 +353,19 @@ static inline void user_enable_block_step(struct task_struct *task)
extern void user_enable_block_step(struct task_struct *);
#endif /* arch_has_block_step */
-#ifdef ARCH_HAS_USER_SINGLE_STEP_INFO
-extern void user_single_step_siginfo(struct task_struct *tsk,
- struct pt_regs *regs, siginfo_t *info);
+#ifdef ARCH_HAS_USER_SINGLE_STEP_REPORT
+extern void user_single_step_report(struct pt_regs *regs);
#else
-static inline void user_single_step_siginfo(struct task_struct *tsk,
- struct pt_regs *regs, siginfo_t *info)
+static inline void user_single_step_report(struct pt_regs *regs)
{
- info->si_signo = SIGTRAP;
+ kernel_siginfo_t info;
+ clear_siginfo(&info);
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = 0;
+ info.si_uid = 0;
+ force_sig_info(info.si_signo, &info, current);
}
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 58e2af8d064b2..adfb3f9a7597e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -962,7 +962,7 @@ struct task_struct {
/* Ptrace state: */
unsigned long ptrace_message;
- siginfo_t *last_siginfo;
+ kernel_siginfo_t *last_siginfo;
struct task_io_accounting ioac;
#ifdef CONFIG_TASK_XACCT
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 1be35729c2c5b..13789d10a50e6 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -270,16 +270,16 @@ static inline int signal_group_exit(const struct signal_struct *sig)
extern void flush_signals(struct task_struct *);
extern void ignore_signals(struct task_struct *);
extern void flush_signal_handlers(struct task_struct *, int force_default);
-extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
+extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *info);
-static inline int kernel_dequeue_signal(siginfo_t *info)
+static inline int kernel_dequeue_signal(void)
{
struct task_struct *tsk = current;
- siginfo_t __info;
+ kernel_siginfo_t __info;
int ret;
spin_lock_irq(&tsk->sighand->siglock);
- ret = dequeue_signal(tsk, &tsk->blocked, info ?: &__info);
+ ret = dequeue_signal(tsk, &tsk->blocked, &__info);
spin_unlock_irq(&tsk->sighand->siglock);
return ret;
@@ -322,12 +322,12 @@ int force_sig_pkuerr(void __user *addr, u32 pkey);
int force_sig_ptrace_errno_trap(int errno, void __user *addr);
-extern int send_sig_info(int, struct siginfo *, struct task_struct *);
+extern int send_sig_info(int, struct kernel_siginfo *, struct task_struct *);
extern void force_sigsegv(int sig, struct task_struct *p);
-extern int force_sig_info(int, struct siginfo *, struct task_struct *);
-extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp);
-extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid);
-extern int kill_pid_info_as_cred(int, struct siginfo *, struct pid *,
+extern int force_sig_info(int, struct kernel_siginfo *, struct task_struct *);
+extern int __kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp);
+extern int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid);
+extern int kill_pid_info_as_cred(int, struct kernel_siginfo *, struct pid *,
const struct cred *);
extern int kill_pgrp(struct pid *pid, int sig, int priv);
extern int kill_pid(struct pid *pid, int sig, int priv);
@@ -475,9 +475,8 @@ static inline int kill_cad_pid(int sig, int priv)
}
/* These can be the second arg to send_sig_info/send_group_sig_info. */
-#define SEND_SIG_NOINFO ((struct siginfo *) 0)
-#define SEND_SIG_PRIV ((struct siginfo *) 1)
-#define SEND_SIG_FORCED ((struct siginfo *) 2)
+#define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0)
+#define SEND_SIG_PRIV ((struct kernel_siginfo *) 1)
/*
* True if we are on the alternate signal stack.
diff --git a/include/linux/security.h b/include/linux/security.h
index 75f4156c84d7d..d170a5b031f38 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -35,7 +35,7 @@
struct linux_binprm;
struct cred;
struct rlimit;
-struct siginfo;
+struct kernel_siginfo;
struct sembuf;
struct kern_ipc_perm;
struct audit_context;
@@ -361,7 +361,7 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource,
int security_task_setscheduler(struct task_struct *p);
int security_task_getscheduler(struct task_struct *p);
int security_task_movememory(struct task_struct *p);
-int security_task_kill(struct task_struct *p, struct siginfo *info,
+int security_task_kill(struct task_struct *p, struct kernel_siginfo *info,
int sig, const struct cred *cred);
int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
@@ -1020,7 +1020,7 @@ static inline int security_task_movememory(struct task_struct *p)
}
static inline int security_task_kill(struct task_struct *p,
- struct siginfo *info, int sig,
+ struct kernel_siginfo *info, int sig,
const struct cred *cred)
{
return 0;
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 3d4cd5db30a96..200ed96a05afe 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -11,17 +11,21 @@ struct task_struct;
/* for sysctl */
extern int print_fatal_signals;
-static inline void copy_siginfo(struct siginfo *to, const struct siginfo *from)
+static inline void copy_siginfo(kernel_siginfo_t *to,
+ const kernel_siginfo_t *from)
{
memcpy(to, from, sizeof(*to));
}
-static inline void clear_siginfo(struct siginfo *info)
+static inline void clear_siginfo(kernel_siginfo_t *info)
{
memset(info, 0, sizeof(*info));
}
-int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from);
+#define SI_EXPANSION_SIZE (sizeof(struct siginfo) - sizeof(struct kernel_siginfo))
+
+int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from);
+int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from);
enum siginfo_layout {
SIL_KILL,
@@ -36,7 +40,7 @@ enum siginfo_layout {
SIL_SYS,
};
-enum siginfo_layout siginfo_layout(int sig, int si_code);
+enum siginfo_layout siginfo_layout(unsigned sig, int si_code);
/*
* Define some primitives to manipulate sigset_t.
@@ -257,11 +261,11 @@ struct pt_regs;
enum pid_type;
extern int next_signal(struct sigpending *pending, sigset_t *mask);
-extern int do_send_sig_info(int sig, struct siginfo *info,
+extern int do_send_sig_info(int sig, struct kernel_siginfo *info,
struct task_struct *p, enum pid_type type);
-extern int group_send_sig_info(int sig, struct siginfo *info,
+extern int group_send_sig_info(int sig, struct kernel_siginfo *info,
struct task_struct *p, enum pid_type type);
-extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
+extern int __group_send_sig_info(int, struct kernel_siginfo *, struct task_struct *);
extern int sigprocmask(int, sigset_t *, sigset_t *);
extern void set_current_blocked(sigset_t *);
extern void __set_current_blocked(const sigset_t *);
diff --git a/include/linux/signal_types.h b/include/linux/signal_types.h
index 222ae696000b9..f8a90ae9c6ec4 100644
--- a/include/linux/signal_types.h
+++ b/include/linux/signal_types.h
@@ -9,6 +9,10 @@
#include <linux/list.h>
#include <uapi/linux/signal.h>
+typedef struct kernel_siginfo {
+ __SIGINFO;
+} kernel_siginfo_t;
+
/*
* Real Time signals may be queued.
*/
@@ -16,7 +20,7 @@
struct sigqueue {
struct list_head list;
int flags;
- siginfo_t info;
+ kernel_siginfo_t info;
struct user_struct *user;
};
@@ -60,7 +64,7 @@ struct old_sigaction {
struct ksignal {
struct k_sigaction ka;
- siginfo_t info;
+ kernel_siginfo_t info;
int sig;
};
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index 05589a3e37f47..40b0b4c1bf7b8 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -123,15 +123,10 @@ static inline __must_check int tracehook_report_syscall_entry(
*/
static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
{
- if (step) {
- siginfo_t info;
- clear_siginfo(&info);
- user_single_step_siginfo(current, regs, &info);
- force_sig_info(SIGTRAP, &info, current);
- return;
- }
-
- ptrace_report_syscall(regs);
+ if (step)
+ user_single_step_report(regs);
+ else
+ ptrace_report_syscall(regs);
}
/**
diff --git a/include/trace/events/signal.h b/include/trace/events/signal.h
index 86582923d51c9..1db7e4b07c014 100644
--- a/include/trace/events/signal.h
+++ b/include/trace/events/signal.h
@@ -11,8 +11,7 @@
#define TP_STORE_SIGINFO(__entry, info) \
do { \
- if (info == SEND_SIG_NOINFO || \
- info == SEND_SIG_FORCED) { \
+ if (info == SEND_SIG_NOINFO) { \
__entry->errno = 0; \
__entry->code = SI_USER; \
} else if (info == SEND_SIG_PRIV) { \
@@ -50,7 +49,7 @@ enum {
*/
TRACE_EVENT(signal_generate,
- TP_PROTO(int sig, struct siginfo *info, struct task_struct *task,
+ TP_PROTO(int sig, struct kernel_siginfo *info, struct task_struct *task,
int group, int result),
TP_ARGS(sig, info, task, group, result),
@@ -96,7 +95,7 @@ TRACE_EVENT(signal_generate,
*/
TRACE_EVENT(signal_deliver,
- TP_PROTO(int sig, struct siginfo *info, struct k_sigaction *ka),
+ TP_PROTO(int sig, struct kernel_siginfo *info, struct k_sigaction *ka),
TP_ARGS(sig, info, ka),
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 80e2a72272053..cb3d6c2671812 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -10,18 +10,7 @@ typedef union sigval {
void __user *sival_ptr;
} sigval_t;
-/*
- * This is the size (including padding) of the part of the
- * struct siginfo that is before the union.
- */
-#ifndef __ARCH_SI_PREAMBLE_SIZE
-#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
-#endif
-
#define SI_MAX_SIZE 128
-#ifndef SI_PAD_SIZE
-#define SI_PAD_SIZE ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int))
-#endif
/*
* The default "si_band" type is "long", as specified by POSIX.
@@ -40,96 +29,108 @@ typedef union sigval {
#define __ARCH_SI_ATTRIBUTES
#endif
-typedef struct siginfo {
- int si_signo;
-#ifndef __ARCH_HAS_SWAPPED_SIGINFO
- int si_errno;
- int si_code;
-#else
- int si_code;
- int si_errno;
-#endif
-
- union {
- int _pad[SI_PAD_SIZE];
-
- /* kill() */
- struct {
- __kernel_pid_t _pid; /* sender's pid */
- __kernel_uid32_t _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- __kernel_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- sigval_t _sigval; /* same as below */
- int _sys_private; /* not to be passed to user */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- __kernel_pid_t _pid; /* sender's pid */
- __kernel_uid32_t _uid; /* sender's uid */
- sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- __kernel_pid_t _pid; /* which child */
- __kernel_uid32_t _uid; /* sender's uid */
- int _status; /* exit code */
- __ARCH_SI_CLOCK_T _utime;
- __ARCH_SI_CLOCK_T _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */
- struct {
- void __user *_addr; /* faulting insn/memory ref. */
+union __sifields {
+ /* kill() */
+ struct {
+ __kernel_pid_t _pid; /* sender's pid */
+ __kernel_uid32_t _uid; /* sender's uid */
+ } _kill;
+
+ /* POSIX.1b timers */
+ struct {
+ __kernel_timer_t _tid; /* timer id */
+ int _overrun; /* overrun count */
+ sigval_t _sigval; /* same as below */
+ int _sys_private; /* not to be passed to user */
+ } _timer;
+
+ /* POSIX.1b signals */
+ struct {
+ __kernel_pid_t _pid; /* sender's pid */
+ __kernel_uid32_t _uid; /* sender's uid */
+ sigval_t _sigval;
+ } _rt;
+
+ /* SIGCHLD */
+ struct {
+ __kernel_pid_t _pid; /* which child */
+ __kernel_uid32_t _uid; /* sender's uid */
+ int _status; /* exit code */
+ __ARCH_SI_CLOCK_T _utime;
+ __ARCH_SI_CLOCK_T _stime;
+ } _sigchld;
+
+ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */
+ struct {
+ void __user *_addr; /* faulting insn/memory ref. */
#ifdef __ARCH_SI_TRAPNO
- int _trapno; /* TRAP # which caused the signal */
+ int _trapno; /* TRAP # which caused the signal */
#endif
#ifdef __ia64__
- int _imm; /* immediate value for "break" */
- unsigned int _flags; /* see ia64 si_flags */
- unsigned long _isr; /* isr */
+ int _imm; /* immediate value for "break" */
+ unsigned int _flags; /* see ia64 si_flags */
+ unsigned long _isr; /* isr */
#endif
#define __ADDR_BND_PKEY_PAD (__alignof__(void *) < sizeof(short) ? \
sizeof(short) : __alignof__(void *))
- union {
- /*
- * used when si_code=BUS_MCEERR_AR or
- * used when si_code=BUS_MCEERR_AO
- */
- short _addr_lsb; /* LSB of the reported address */
- /* used when si_code=SEGV_BNDERR */
- struct {
- char _dummy_bnd[__ADDR_BND_PKEY_PAD];
- void __user *_lower;
- void __user *_upper;
- } _addr_bnd;
- /* used when si_code=SEGV_PKUERR */
- struct {
- char _dummy_pkey[__ADDR_BND_PKEY_PAD];
- __u32 _pkey;
- } _addr_pkey;
- };
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
+ union {
+ /*
+ * used when si_code=BUS_MCEERR_AR or
+ * used when si_code=BUS_MCEERR_AO
+ */
+ short _addr_lsb; /* LSB of the reported address */
+ /* used when si_code=SEGV_BNDERR */
+ struct {
+ char _dummy_bnd[__ADDR_BND_PKEY_PAD];
+ void __user *_lower;
+ void __user *_upper;
+ } _addr_bnd;
+ /* used when si_code=SEGV_PKUERR */
+ struct {
+ char _dummy_pkey[__ADDR_BND_PKEY_PAD];
+ __u32 _pkey;
+ } _addr_pkey;
+ };
+ } _sigfault;
+
+ /* SIGPOLL */
+ struct {
+ __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ int _fd;
+ } _sigpoll;
+
+ /* SIGSYS */
+ struct {
+ void __user *_call_addr; /* calling user insn */
+ int _syscall; /* triggering system call number */
+ unsigned int _arch; /* AUDIT_ARCH_* of syscall */
+ } _sigsys;
+};
- /* SIGSYS */
- struct {
- void __user *_call_addr; /* calling user insn */
- int _syscall; /* triggering system call number */
- unsigned int _arch; /* AUDIT_ARCH_* of syscall */
- } _sigsys;
- } _sifields;
+#ifndef __ARCH_HAS_SWAPPED_SIGINFO
+#define __SIGINFO \
+struct { \
+ int si_signo; \
+ int si_errno; \
+ int si_code; \
+ union __sifields _sifields; \
+}
+#else
+#define __SIGINFO \
+struct { \
+ int si_signo; \
+ int si_code; \
+ int si_errno; \
+ union __sifields _sifields; \
+}
+#endif /* __ARCH_HAS_SWAPPED_SIGINFO */
+
+typedef struct siginfo {
+ union {
+ __SIGINFO;
+ int _si_pad[SI_MAX_SIZE/sizeof(int)];
+ };
} __ARCH_SI_ATTRIBUTES siginfo_t;
/*
@@ -286,6 +287,12 @@ typedef struct siginfo {
#define NSIGSYS 1
/*
+ * SIGEMT si_codes
+ */
+#define EMT_TAGOVF 1 /* tag overflow */
+#define NSIGEMT 1
+
+/*
* sigevent definitions
*
* It seems likely that SIGEV_THREAD will have to be handled from
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c0d58f390c3b4..cc41de3b8debf 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -655,7 +655,7 @@ static void __do_notify(struct mqueue_inode_info *info)
* synchronously. */
if (info->notify_owner &&
info->attr.mq_curmsgs == 1) {
- struct siginfo sig_i;
+ struct kernel_siginfo sig_i;
switch (info->notify.sigev_notify) {
case SIGEV_NONE:
break;
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 3207a4d26849e..2bf792d22087c 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1858,7 +1858,7 @@ static void handle_trampoline(struct pt_regs *regs)
sigill:
uprobe_warn(current, "handle uretprobe, sending SIGILL.");
- force_sig_info(SIGILL, SEND_SIG_FORCED, current);
+ force_sig(SIGILL, current);
}
@@ -1966,7 +1966,7 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs)
if (unlikely(err)) {
uprobe_warn(current, "execute the probed insn, sending SIGILL.");
- force_sig_info(SIGILL, SEND_SIG_FORCED, current);
+ force_sig(SIGILL, current);
}
}
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 2a2ac53d8b8bb..aa6e72fb7c089 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -216,7 +216,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
idr_for_each_entry_continue(&pid_ns->idr, pid, nr) {
task = pid_task(pid, PIDTYPE_PID);
if (task && !__fatal_signal_pending(task))
- send_sig_info(SIGKILL, SEND_SIG_FORCED, task);
+ group_send_sig_info(SIGKILL, SEND_SIG_PRIV, task, PIDTYPE_MAX);
}
read_unlock(&tasklist_lock);
rcu_read_unlock();
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 99cfddde6a559..80b34dffdfb9b 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -406,7 +406,7 @@ static int ptrace_attach(struct task_struct *task, long request,
/* SEIZE doesn't trap tracee on attach */
if (!seize)
- send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);
+ send_sig_info(SIGSTOP, SEND_SIG_PRIV, task);
spin_lock(&task->sighand->siglock);
@@ -573,7 +573,7 @@ void exit_ptrace(struct task_struct *tracer, struct list_head *dead)
list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
if (unlikely(p->ptrace & PT_EXITKILL))
- send_sig_info(SIGKILL, SEND_SIG_FORCED, p);
+ send_sig_info(SIGKILL, SEND_SIG_PRIV, p);
if (__ptrace_detach(tracer, p))
list_add(&p->ptrace_entry, dead);
@@ -661,7 +661,7 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data)
return 0;
}
-static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
+static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info)
{
unsigned long flags;
int error = -ESRCH;
@@ -677,7 +677,7 @@ static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
return error;
}
-static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
+static int ptrace_setsiginfo(struct task_struct *child, const kernel_siginfo_t *info)
{
unsigned long flags;
int error = -ESRCH;
@@ -719,7 +719,7 @@ static int ptrace_peek_siginfo(struct task_struct *child,
pending = &child->pending;
for (i = 0; i < arg.nr; ) {
- siginfo_t info;
+ kernel_siginfo_t info;
s32 off = arg.off + i;
spin_lock_irq(&child->sighand->siglock);
@@ -895,7 +895,7 @@ int ptrace_request(struct task_struct *child, long request,
{
bool seized = child->ptrace & PT_SEIZED;
int ret = -EIO;
- siginfo_t siginfo, *si;
+ kernel_siginfo_t siginfo, *si;
void __user *datavp = (void __user *) data;
unsigned long __user *datalp = datavp;
unsigned long flags;
@@ -929,9 +929,8 @@ int ptrace_request(struct task_struct *child, long request,
break;
case PTRACE_SETSIGINFO:
- if (copy_from_user(&siginfo, datavp, sizeof siginfo))
- ret = -EFAULT;
- else
+ ret = copy_siginfo_from_user(&siginfo, datavp);
+ if (!ret)
ret = ptrace_setsiginfo(child, &siginfo);
break;
@@ -1191,7 +1190,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
{
compat_ulong_t __user *datap = compat_ptr(data);
compat_ulong_t word;
- siginfo_t siginfo;
+ kernel_siginfo_t siginfo;
int ret;
switch (request) {
@@ -1225,10 +1224,9 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
break;
case PTRACE_SETSIGINFO:
- if (copy_siginfo_from_user32(
- &siginfo, (struct compat_siginfo __user *) datap))
- ret = -EFAULT;
- else
+ ret = copy_siginfo_from_user32(
+ &siginfo, (struct compat_siginfo __user *) datap);
+ if (!ret)
ret = ptrace_setsiginfo(child, &siginfo);
break;
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index fd023ac24e10e..4d7809cdd27dd 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -522,7 +522,7 @@ void put_seccomp_filter(struct task_struct *tsk)
__put_seccomp_filter(tsk->seccomp.filter);
}
-static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason)
+static void seccomp_init_siginfo(kernel_siginfo_t *info, int syscall, int reason)
{
clear_siginfo(info);
info->si_signo = SIGSYS;
@@ -542,7 +542,7 @@ static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason)
*/
static void seccomp_send_sigsys(int syscall, int reason)
{
- struct siginfo info;
+ struct kernel_siginfo info;
seccomp_init_siginfo(&info, syscall, reason);
force_sig_info(SIGSYS, &info, current);
}
@@ -747,7 +747,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
/* Dump core only if this is the last remaining thread. */
if (action == SECCOMP_RET_KILL_PROCESS ||
get_nr_threads(current) == 1) {
- siginfo_t info;
+ kernel_siginfo_t info;
/* Show the original registers in the dump. */
syscall_rollback(current, task_pt_regs(current));
diff --git a/kernel/signal.c b/kernel/signal.c
index e4aad0e908827..dbd2e4db24cf4 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -78,6 +78,10 @@ static bool sig_task_ignored(struct task_struct *t, int sig, bool force)
handler = sig_handler(t, sig);
+ /* SIGKILL and SIGSTOP may not be sent to the global init */
+ if (unlikely(is_global_init(t) && sig_kernel_only(sig)))
+ return true;
+
if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
handler == SIG_DFL && !(force && sig_kernel_only(sig)))
return true;
@@ -172,6 +176,7 @@ void recalc_sigpending(void)
clear_thread_flag(TIF_SIGPENDING);
}
+EXPORT_SYMBOL(recalc_sigpending);
void calculate_sigpending(void)
{
@@ -462,6 +467,7 @@ void flush_signals(struct task_struct *t)
flush_sigqueue(&t->signal->shared_pending);
spin_unlock_irqrestore(&t->sighand->siglock, flags);
}
+EXPORT_SYMBOL(flush_signals);
#ifdef CONFIG_POSIX_TIMERS
static void __flush_itimer_signals(struct sigpending *pending)
@@ -543,7 +549,7 @@ bool unhandled_signal(struct task_struct *tsk, int sig)
return !tsk->ptrace;
}
-static void collect_signal(int sig, struct sigpending *list, siginfo_t *info,
+static void collect_signal(int sig, struct sigpending *list, kernel_siginfo_t *info,
bool *resched_timer)
{
struct sigqueue *q, *first = NULL;
@@ -589,7 +595,7 @@ still_pending:
}
static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
- siginfo_t *info, bool *resched_timer)
+ kernel_siginfo_t *info, bool *resched_timer)
{
int sig = next_signal(pending, mask);
@@ -604,7 +610,7 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
*
* All callers have to hold the siglock.
*/
-int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
+int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *info)
{
bool resched_timer = false;
int signr;
@@ -680,6 +686,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
#endif
return signr;
}
+EXPORT_SYMBOL_GPL(dequeue_signal);
/*
* Tell a process that it has a new active signal..
@@ -730,12 +737,12 @@ static void flush_sigqueue_mask(sigset_t *mask, struct sigpending *s)
}
}
-static inline int is_si_special(const struct siginfo *info)
+static inline int is_si_special(const struct kernel_siginfo *info)
{
- return info <= SEND_SIG_FORCED;
+ return info <= SEND_SIG_PRIV;
}
-static inline bool si_fromuser(const struct siginfo *info)
+static inline bool si_fromuser(const struct kernel_siginfo *info)
{
return info == SEND_SIG_NOINFO ||
(!is_si_special(info) && SI_FROMUSER(info));
@@ -760,7 +767,7 @@ static bool kill_ok_by_cred(struct task_struct *t)
* Bad permissions for sending the signal
* - the caller must hold the RCU read lock
*/
-static int check_kill_permission(int sig, struct siginfo *info,
+static int check_kill_permission(int sig, struct kernel_siginfo *info,
struct task_struct *t)
{
struct pid *sid;
@@ -1003,7 +1010,7 @@ static inline bool legacy_queue(struct sigpending *signals, int sig)
}
#ifdef CONFIG_USER_NS
-static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
+static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t)
{
if (current_user_ns() == task_cred_xxx(t, user_ns))
return;
@@ -1017,13 +1024,13 @@ static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_str
rcu_read_unlock();
}
#else
-static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
+static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t)
{
return;
}
#endif
-static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
+static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t,
enum pid_type type, int from_ancestor_ns)
{
struct sigpending *pending;
@@ -1035,7 +1042,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
result = TRACE_SIGNAL_IGNORED;
if (!prepare_signal(sig, t,
- from_ancestor_ns || (info == SEND_SIG_FORCED)))
+ from_ancestor_ns || (info == SEND_SIG_PRIV)))
goto ret;
pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
@@ -1050,10 +1057,10 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
result = TRACE_SIGNAL_DELIVERED;
/*
- * fast-pathed signals for kernel-internal things like SIGSTOP
- * or SIGKILL.
+ * Skip useless siginfo allocation for SIGKILL SIGSTOP,
+ * and kernel threads.
*/
- if (info == SEND_SIG_FORCED)
+ if (sig_kernel_only(sig) || (t->flags & PF_KTHREAD))
goto out_set;
/*
@@ -1143,7 +1150,7 @@ ret:
return ret;
}
-static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
+static int send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t,
enum pid_type type)
{
int from_ancestor_ns = 0;
@@ -1190,18 +1197,12 @@ static int __init setup_print_fatal_signals(char *str)
__setup("print-fatal-signals=", setup_print_fatal_signals);
int
-__group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+__group_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p)
{
return send_signal(sig, info, p, PIDTYPE_TGID);
}
-static int
-specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
-{
- return send_signal(sig, info, t, PIDTYPE_PID);
-}
-
-int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
+int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p,
enum pid_type type)
{
unsigned long flags;
@@ -1227,7 +1228,7 @@ int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
* that is why we also clear SIGNAL_UNKILLABLE.
*/
int
-force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
+force_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *t)
{
unsigned long int flags;
int ret, blocked, ignored;
@@ -1250,7 +1251,7 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
*/
if (action->sa.sa_handler == SIG_DFL && !t->ptrace)
t->signal->flags &= ~SIGNAL_UNKILLABLE;
- ret = specific_send_sig_info(sig, info, t);
+ ret = send_signal(sig, info, t, PIDTYPE_PID);
spin_unlock_irqrestore(&t->sighand->siglock, flags);
return ret;
@@ -1315,8 +1316,8 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
/*
* send signal info to all the members of a group
*/
-int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
- enum pid_type type)
+int group_send_sig_info(int sig, struct kernel_siginfo *info,
+ struct task_struct *p, enum pid_type type)
{
int ret;
@@ -1335,7 +1336,7 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
* control characters do (^C, ^Z etc)
* - the caller must hold at least a readlock on tasklist_lock
*/
-int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
+int __kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp)
{
struct task_struct *p = NULL;
int retval, success;
@@ -1350,7 +1351,7 @@ int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
return success ? 0 : retval;
}
-int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
+int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
{
int error = -ESRCH;
struct task_struct *p;
@@ -1372,7 +1373,7 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
}
}
-static int kill_proc_info(int sig, struct siginfo *info, pid_t pid)
+static int kill_proc_info(int sig, struct kernel_siginfo *info, pid_t pid)
{
int error;
rcu_read_lock();
@@ -1393,7 +1394,7 @@ static inline bool kill_as_cred_perm(const struct cred *cred,
}
/* like kill_pid_info(), but doesn't use uid/euid of "current" */
-int kill_pid_info_as_cred(int sig, struct siginfo *info, struct pid *pid,
+int kill_pid_info_as_cred(int sig, struct kernel_siginfo *info, struct pid *pid,
const struct cred *cred)
{
int ret = -EINVAL;
@@ -1437,7 +1438,7 @@ EXPORT_SYMBOL_GPL(kill_pid_info_as_cred);
* is probably wrong. Should make it like BSD or SYSV.
*/
-static int kill_something_info(int sig, struct siginfo *info, pid_t pid)
+static int kill_something_info(int sig, struct kernel_siginfo *info, pid_t pid)
{
int ret;
@@ -1481,7 +1482,7 @@ static int kill_something_info(int sig, struct siginfo *info, pid_t pid)
* These are for backward compatibility with the rest of the kernel source.
*/
-int send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+int send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p)
{
/*
* Make sure legacy kernel users don't send in bad values
@@ -1492,6 +1493,7 @@ int send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
return do_send_sig_info(sig, info, p, PIDTYPE_PID);
}
+EXPORT_SYMBOL(send_sig_info);
#define __si_special(priv) \
((priv) ? SEND_SIG_PRIV : SEND_SIG_NOINFO)
@@ -1501,11 +1503,13 @@ send_sig(int sig, struct task_struct *p, int priv)
{
return send_sig_info(sig, __si_special(priv), p);
}
+EXPORT_SYMBOL(send_sig);
void force_sig(int sig, struct task_struct *p)
{
force_sig_info(sig, SEND_SIG_PRIV, p);
}
+EXPORT_SYMBOL(force_sig);
/*
* When things go south during signal handling, we
@@ -1529,7 +1533,7 @@ int force_sig_fault(int sig, int code, void __user *addr
___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
, struct task_struct *t)
{
- struct siginfo info;
+ struct kernel_siginfo info;
clear_siginfo(&info);
info.si_signo = sig;
@@ -1552,7 +1556,7 @@ int send_sig_fault(int sig, int code, void __user *addr
___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
, struct task_struct *t)
{
- struct siginfo info;
+ struct kernel_siginfo info;
clear_siginfo(&info);
info.si_signo = sig;
@@ -1572,7 +1576,7 @@ int send_sig_fault(int sig, int code, void __user *addr
int force_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t)
{
- struct siginfo info;
+ struct kernel_siginfo info;
WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
clear_siginfo(&info);
@@ -1586,7 +1590,7 @@ int force_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct
int send_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t)
{
- struct siginfo info;
+ struct kernel_siginfo info;
WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
clear_siginfo(&info);
@@ -1601,7 +1605,7 @@ EXPORT_SYMBOL(send_sig_mceerr);
int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)
{
- struct siginfo info;
+ struct kernel_siginfo info;
clear_siginfo(&info);
info.si_signo = SIGSEGV;
@@ -1616,7 +1620,7 @@ int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)
#ifdef SEGV_PKUERR
int force_sig_pkuerr(void __user *addr, u32 pkey)
{
- struct siginfo info;
+ struct kernel_siginfo info;
clear_siginfo(&info);
info.si_signo = SIGSEGV;
@@ -1633,7 +1637,7 @@ int force_sig_pkuerr(void __user *addr, u32 pkey)
*/
int force_sig_ptrace_errno_trap(int errno, void __user *addr)
{
- struct siginfo info;
+ struct kernel_siginfo info;
clear_siginfo(&info);
info.si_signo = SIGTRAP;
@@ -1762,7 +1766,7 @@ ret:
*/
bool do_notify_parent(struct task_struct *tsk, int sig)
{
- struct siginfo info;
+ struct kernel_siginfo info;
unsigned long flags;
struct sighand_struct *psig;
bool autoreap = false;
@@ -1867,7 +1871,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
static void do_notify_parent_cldstop(struct task_struct *tsk,
bool for_ptracer, int why)
{
- struct siginfo info;
+ struct kernel_siginfo info;
unsigned long flags;
struct task_struct *parent;
struct sighand_struct *sighand;
@@ -1967,7 +1971,7 @@ static bool sigkill_pending(struct task_struct *tsk)
* If we actually decide not to stop at all because the tracer
* is gone, we keep current->exit_code unless clear_code.
*/
-static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
+static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t *info)
__releases(&current->sighand->siglock)
__acquires(&current->sighand->siglock)
{
@@ -2104,7 +2108,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
static void ptrace_do_notify(int signr, int exit_code, int why)
{
- siginfo_t info;
+ kernel_siginfo_t info;
clear_siginfo(&info);
info.si_signo = signr;
@@ -2285,7 +2289,7 @@ static void do_jobctl_trap(void)
}
}
-static int ptrace_signal(int signr, siginfo_t *info)
+static int ptrace_signal(int signr, kernel_siginfo_t *info)
{
/*
* We do not check sig_kernel_stop(signr) but set this marker
@@ -2326,7 +2330,7 @@ static int ptrace_signal(int signr, siginfo_t *info)
/* If the (new) signal is now blocked, requeue it. */
if (sigismember(&current->blocked, signr)) {
- specific_send_sig_info(signr, info, current);
+ send_signal(signr, info, current, PIDTYPE_PID);
signr = 0;
}
@@ -2636,14 +2640,6 @@ out:
}
}
-EXPORT_SYMBOL(recalc_sigpending);
-EXPORT_SYMBOL_GPL(dequeue_signal);
-EXPORT_SYMBOL(flush_signals);
-EXPORT_SYMBOL(force_sig);
-EXPORT_SYMBOL(send_sig);
-EXPORT_SYMBOL(send_sig_info);
-EXPORT_SYMBOL(sigprocmask);
-
/*
* System call entry points.
*/
@@ -2737,6 +2733,7 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
__set_current_blocked(&newset);
return 0;
}
+EXPORT_SYMBOL(sigprocmask);
/**
* sys_rt_sigprocmask - change the list of currently blocked signals
@@ -2847,27 +2844,48 @@ COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset,
}
#endif
-enum siginfo_layout siginfo_layout(int sig, int si_code)
+static const struct {
+ unsigned char limit, layout;
+} sig_sicodes[] = {
+ [SIGILL] = { NSIGILL, SIL_FAULT },
+ [SIGFPE] = { NSIGFPE, SIL_FAULT },
+ [SIGSEGV] = { NSIGSEGV, SIL_FAULT },
+ [SIGBUS] = { NSIGBUS, SIL_FAULT },
+ [SIGTRAP] = { NSIGTRAP, SIL_FAULT },
+#if defined(SIGEMT)
+ [SIGEMT] = { NSIGEMT, SIL_FAULT },
+#endif
+ [SIGCHLD] = { NSIGCHLD, SIL_CHLD },
+ [SIGPOLL] = { NSIGPOLL, SIL_POLL },
+ [SIGSYS] = { NSIGSYS, SIL_SYS },
+};
+
+static bool known_siginfo_layout(unsigned sig, int si_code)
+{
+ if (si_code == SI_KERNEL)
+ return true;
+ else if ((si_code > SI_USER)) {
+ if (sig_specific_sicodes(sig)) {
+ if (si_code <= sig_sicodes[sig].limit)
+ return true;
+ }
+ else if (si_code <= NSIGPOLL)
+ return true;
+ }
+ else if (si_code >= SI_DETHREAD)
+ return true;
+ else if (si_code == SI_ASYNCNL)
+ return true;
+ return false;
+}
+
+enum siginfo_layout siginfo_layout(unsigned sig, int si_code)
{
enum siginfo_layout layout = SIL_KILL;
if ((si_code > SI_USER) && (si_code < SI_KERNEL)) {
- static const struct {
- unsigned char limit, layout;
- } filter[] = {
- [SIGILL] = { NSIGILL, SIL_FAULT },
- [SIGFPE] = { NSIGFPE, SIL_FAULT },
- [SIGSEGV] = { NSIGSEGV, SIL_FAULT },
- [SIGBUS] = { NSIGBUS, SIL_FAULT },
- [SIGTRAP] = { NSIGTRAP, SIL_FAULT },
-#if defined(SIGEMT) && defined(NSIGEMT)
- [SIGEMT] = { NSIGEMT, SIL_FAULT },
-#endif
- [SIGCHLD] = { NSIGCHLD, SIL_CHLD },
- [SIGPOLL] = { NSIGPOLL, SIL_POLL },
- [SIGSYS] = { NSIGSYS, SIL_SYS },
- };
- if ((sig < ARRAY_SIZE(filter)) && (si_code <= filter[sig].limit)) {
- layout = filter[sig].layout;
+ if ((sig < ARRAY_SIZE(sig_sicodes)) &&
+ (si_code <= sig_sicodes[sig].limit)) {
+ layout = sig_sicodes[sig].layout;
/* Handle the exceptions */
if ((sig == SIGBUS) &&
(si_code >= BUS_MCEERR_AR) && (si_code <= BUS_MCEERR_AO))
@@ -2892,22 +2910,69 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)
return layout;
}
-int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
+static inline char __user *si_expansion(const siginfo_t __user *info)
+{
+ return ((char __user *)info) + sizeof(struct kernel_siginfo);
+}
+
+int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from)
{
- if (copy_to_user(to, from , sizeof(struct siginfo)))
+ char __user *expansion = si_expansion(to);
+ if (copy_to_user(to, from , sizeof(struct kernel_siginfo)))
+ return -EFAULT;
+ if (clear_user(expansion, SI_EXPANSION_SIZE))
return -EFAULT;
return 0;
}
+static int post_copy_siginfo_from_user(kernel_siginfo_t *info,
+ const siginfo_t __user *from)
+{
+ if (unlikely(!known_siginfo_layout(info->si_signo, info->si_code))) {
+ char __user *expansion = si_expansion(from);
+ char buf[SI_EXPANSION_SIZE];
+ int i;
+ /*
+ * An unknown si_code might need more than
+ * sizeof(struct kernel_siginfo) bytes. Verify all of the
+ * extra bytes are 0. This guarantees copy_siginfo_to_user
+ * will return this data to userspace exactly.
+ */
+ if (copy_from_user(&buf, expansion, SI_EXPANSION_SIZE))
+ return -EFAULT;
+ for (i = 0; i < SI_EXPANSION_SIZE; i++) {
+ if (buf[i] != 0)
+ return -E2BIG;
+ }
+ }
+ return 0;
+}
+
+static int __copy_siginfo_from_user(int signo, kernel_siginfo_t *to,
+ const siginfo_t __user *from)
+{
+ if (copy_from_user(to, from, sizeof(struct kernel_siginfo)))
+ return -EFAULT;
+ to->si_signo = signo;
+ return post_copy_siginfo_from_user(to, from);
+}
+
+int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)
+{
+ if (copy_from_user(to, from, sizeof(struct kernel_siginfo)))
+ return -EFAULT;
+ return post_copy_siginfo_from_user(to, from);
+}
+
#ifdef CONFIG_COMPAT
int copy_siginfo_to_user32(struct compat_siginfo __user *to,
- const struct siginfo *from)
+ const struct kernel_siginfo *from)
#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION)
{
return __copy_siginfo_to_user32(to, from, in_x32_syscall());
}
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
- const struct siginfo *from, bool x32_ABI)
+ const struct kernel_siginfo *from, bool x32_ABI)
#endif
{
struct compat_siginfo new;
@@ -2991,88 +3056,106 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
return 0;
}
-int copy_siginfo_from_user32(struct siginfo *to,
- const struct compat_siginfo __user *ufrom)
+static int post_copy_siginfo_from_user32(kernel_siginfo_t *to,
+ const struct compat_siginfo *from)
{
- struct compat_siginfo from;
-
- if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo)))
- return -EFAULT;
-
clear_siginfo(to);
- to->si_signo = from.si_signo;
- to->si_errno = from.si_errno;
- to->si_code = from.si_code;
- switch(siginfo_layout(from.si_signo, from.si_code)) {
+ to->si_signo = from->si_signo;
+ to->si_errno = from->si_errno;
+ to->si_code = from->si_code;
+ switch(siginfo_layout(from->si_signo, from->si_code)) {
case SIL_KILL:
- to->si_pid = from.si_pid;
- to->si_uid = from.si_uid;
+ to->si_pid = from->si_pid;
+ to->si_uid = from->si_uid;
break;
case SIL_TIMER:
- to->si_tid = from.si_tid;
- to->si_overrun = from.si_overrun;
- to->si_int = from.si_int;
+ to->si_tid = from->si_tid;
+ to->si_overrun = from->si_overrun;
+ to->si_int = from->si_int;
break;
case SIL_POLL:
- to->si_band = from.si_band;
- to->si_fd = from.si_fd;
+ to->si_band = from->si_band;
+ to->si_fd = from->si_fd;
break;
case SIL_FAULT:
- to->si_addr = compat_ptr(from.si_addr);
+ to->si_addr = compat_ptr(from->si_addr);
#ifdef __ARCH_SI_TRAPNO
- to->si_trapno = from.si_trapno;
+ to->si_trapno = from->si_trapno;
#endif
break;
case SIL_FAULT_MCEERR:
- to->si_addr = compat_ptr(from.si_addr);
+ to->si_addr = compat_ptr(from->si_addr);
#ifdef __ARCH_SI_TRAPNO
- to->si_trapno = from.si_trapno;
+ to->si_trapno = from->si_trapno;
#endif
- to->si_addr_lsb = from.si_addr_lsb;
+ to->si_addr_lsb = from->si_addr_lsb;
break;
case SIL_FAULT_BNDERR:
- to->si_addr = compat_ptr(from.si_addr);
+ to->si_addr = compat_ptr(from->si_addr);
#ifdef __ARCH_SI_TRAPNO
- to->si_trapno = from.si_trapno;
+ to->si_trapno = from->si_trapno;
#endif
- to->si_lower = compat_ptr(from.si_lower);
- to->si_upper = compat_ptr(from.si_upper);
+ to->si_lower = compat_ptr(from->si_lower);
+ to->si_upper = compat_ptr(from->si_upper);
break;
case SIL_FAULT_PKUERR:
- to->si_addr = compat_ptr(from.si_addr);
+ to->si_addr = compat_ptr(from->si_addr);
#ifdef __ARCH_SI_TRAPNO
- to->si_trapno = from.si_trapno;
+ to->si_trapno = from->si_trapno;
#endif
- to->si_pkey = from.si_pkey;
+ to->si_pkey = from->si_pkey;
break;
case SIL_CHLD:
- to->si_pid = from.si_pid;
- to->si_uid = from.si_uid;
- to->si_status = from.si_status;
+ to->si_pid = from->si_pid;
+ to->si_uid = from->si_uid;
+ to->si_status = from->si_status;
#ifdef CONFIG_X86_X32_ABI
if (in_x32_syscall()) {
- to->si_utime = from._sifields._sigchld_x32._utime;
- to->si_stime = from._sifields._sigchld_x32._stime;
+ to->si_utime = from->_sifields._sigchld_x32._utime;
+ to->si_stime = from->_sifields._sigchld_x32._stime;
} else
#endif
{
- to->si_utime = from.si_utime;
- to->si_stime = from.si_stime;
+ to->si_utime = from->si_utime;
+ to->si_stime = from->si_stime;
}
break;
case SIL_RT:
- to->si_pid = from.si_pid;
- to->si_uid = from.si_uid;
- to->si_int = from.si_int;
+ to->si_pid = from->si_pid;
+ to->si_uid = from->si_uid;
+ to->si_int = from->si_int;
break;
case SIL_SYS:
- to->si_call_addr = compat_ptr(from.si_call_addr);
- to->si_syscall = from.si_syscall;
- to->si_arch = from.si_arch;
+ to->si_call_addr = compat_ptr(from->si_call_addr);
+ to->si_syscall = from->si_syscall;
+ to->si_arch = from->si_arch;
break;
}
return 0;
}
+
+static int __copy_siginfo_from_user32(int signo, struct kernel_siginfo *to,
+ const struct compat_siginfo __user *ufrom)
+{
+ struct compat_siginfo from;
+
+ if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo)))
+ return -EFAULT;
+
+ from.si_signo = signo;
+ return post_copy_siginfo_from_user32(to, &from);
+}
+
+int copy_siginfo_from_user32(struct kernel_siginfo *to,
+ const struct compat_siginfo __user *ufrom)
+{
+ struct compat_siginfo from;
+
+ if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo)))
+ return -EFAULT;
+
+ return post_copy_siginfo_from_user32(to, &from);
+}
#endif /* CONFIG_COMPAT */
/**
@@ -3081,7 +3164,7 @@ int copy_siginfo_from_user32(struct siginfo *to,
* @info: if non-null, the signal's siginfo is returned here
* @ts: upper bound on process time suspension
*/
-static int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
+static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info,
const struct timespec *ts)
{
ktime_t *to = NULL, timeout = KTIME_MAX;
@@ -3145,7 +3228,7 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
{
sigset_t these;
struct timespec ts;
- siginfo_t info;
+ kernel_siginfo_t info;
int ret;
/* XXX: Don't preclude handling different sized sigset_t's. */
@@ -3177,7 +3260,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
{
sigset_t s;
struct timespec t;
- siginfo_t info;
+ kernel_siginfo_t info;
long ret;
if (sigsetsize != sizeof(sigset_t))
@@ -3209,7 +3292,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
*/
SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
{
- struct siginfo info;
+ struct kernel_siginfo info;
clear_siginfo(&info);
info.si_signo = sig;
@@ -3222,7 +3305,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
}
static int
-do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
+do_send_specific(pid_t tgid, pid_t pid, int sig, struct kernel_siginfo *info)
{
struct task_struct *p;
int error = -ESRCH;
@@ -3253,7 +3336,7 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
static int do_tkill(pid_t tgid, pid_t pid, int sig)
{
- struct siginfo info;
+ struct kernel_siginfo info;
clear_siginfo(&info);
info.si_signo = sig;
@@ -3300,7 +3383,7 @@ SYSCALL_DEFINE2(tkill, pid_t, pid, int, sig)
return do_tkill(0, pid, sig);
}
-static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info)
+static int do_rt_sigqueueinfo(pid_t pid, int sig, kernel_siginfo_t *info)
{
/* Not even root can pretend to send signals from the kernel.
* Nor can they impersonate a kill()/tgkill(), which adds source info.
@@ -3309,8 +3392,6 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info)
(task_pid_vnr(current) != pid))
return -EPERM;
- info->si_signo = sig;
-
/* POSIX.1b doesn't mention process groups. */
return kill_proc_info(sig, info, pid);
}
@@ -3324,9 +3405,10 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info)
SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig,
siginfo_t __user *, uinfo)
{
- siginfo_t info;
- if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
- return -EFAULT;
+ kernel_siginfo_t info;
+ int ret = __copy_siginfo_from_user(sig, &info, uinfo);
+ if (unlikely(ret))
+ return ret;
return do_rt_sigqueueinfo(pid, sig, &info);
}
@@ -3336,15 +3418,15 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo,
int, sig,
struct compat_siginfo __user *, uinfo)
{
- siginfo_t info;
- int ret = copy_siginfo_from_user32(&info, uinfo);
+ kernel_siginfo_t info;
+ int ret = __copy_siginfo_from_user32(sig, &info, uinfo);
if (unlikely(ret))
return ret;
return do_rt_sigqueueinfo(pid, sig, &info);
}
#endif
-static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info)
+static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, kernel_siginfo_t *info)
{
/* This is only valid for single tasks */
if (pid <= 0 || tgid <= 0)
@@ -3357,19 +3439,16 @@ static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info)
(task_pid_vnr(current) != pid))
return -EPERM;
- info->si_signo = sig;
-
return do_send_specific(tgid, pid, sig, info);
}
SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig,
siginfo_t __user *, uinfo)
{
- siginfo_t info;
-
- if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
- return -EFAULT;
-
+ kernel_siginfo_t info;
+ int ret = __copy_siginfo_from_user(sig, &info, uinfo);
+ if (unlikely(ret))
+ return ret;
return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
}
@@ -3380,10 +3459,10 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
int, sig,
struct compat_siginfo __user *, uinfo)
{
- siginfo_t info;
-
- if (copy_siginfo_from_user32(&info, uinfo))
- return -EFAULT;
+ kernel_siginfo_t info;
+ int ret = __copy_siginfo_from_user32(sig, &info, uinfo);
+ if (unlikely(ret))
+ return ret;
return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
}
#endif
@@ -3966,13 +4045,57 @@ __weak const char *arch_vma_name(struct vm_area_struct *vma)
return NULL;
}
-void __init signals_init(void)
+static inline void siginfo_buildtime_checks(void)
{
- /* If this check fails, the __ARCH_SI_PREAMBLE_SIZE value is wrong! */
- BUILD_BUG_ON(__ARCH_SI_PREAMBLE_SIZE
- != offsetof(struct siginfo, _sifields._pad));
BUILD_BUG_ON(sizeof(struct siginfo) != SI_MAX_SIZE);
+ /* Verify the offsets in the two siginfos match */
+#define CHECK_OFFSET(field) \
+ BUILD_BUG_ON(offsetof(siginfo_t, field) != offsetof(kernel_siginfo_t, field))
+
+ /* kill */
+ CHECK_OFFSET(si_pid);
+ CHECK_OFFSET(si_uid);
+
+ /* timer */
+ CHECK_OFFSET(si_tid);
+ CHECK_OFFSET(si_overrun);
+ CHECK_OFFSET(si_value);
+
+ /* rt */
+ CHECK_OFFSET(si_pid);
+ CHECK_OFFSET(si_uid);
+ CHECK_OFFSET(si_value);
+
+ /* sigchld */
+ CHECK_OFFSET(si_pid);
+ CHECK_OFFSET(si_uid);
+ CHECK_OFFSET(si_status);
+ CHECK_OFFSET(si_utime);
+ CHECK_OFFSET(si_stime);
+
+ /* sigfault */
+ CHECK_OFFSET(si_addr);
+ CHECK_OFFSET(si_addr_lsb);
+ CHECK_OFFSET(si_lower);
+ CHECK_OFFSET(si_upper);
+ CHECK_OFFSET(si_pkey);
+
+ /* sigpoll */
+ CHECK_OFFSET(si_band);
+ CHECK_OFFSET(si_fd);
+
+ /* sigsys */
+ CHECK_OFFSET(si_call_addr);
+ CHECK_OFFSET(si_syscall);
+ CHECK_OFFSET(si_arch);
+#undef CHECK_OFFSET
+}
+
+void __init signals_init(void)
+{
+ siginfo_buildtime_checks();
+
sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC);
}
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 4b9127e95430b..eabb4c22728de 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -308,7 +308,7 @@ static void common_hrtimer_rearm(struct k_itimer *timr)
* To protect against the timer going away while the interrupt is queued,
* we require that the it_requeue_pending flag be set.
*/
-void posixtimer_rearm(struct siginfo *info)
+void posixtimer_rearm(struct kernel_siginfo *info)
{
struct k_itimer *timr;
unsigned long flags;
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index f10aa5360616e..6589f60d50186 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -859,7 +859,7 @@ static void __oom_kill_process(struct task_struct *victim)
* in order to prevent the OOM victim from depleting the memory
* reserves from the user space under its control.
*/
- do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, PIDTYPE_TGID);
+ do_send_sig_info(SIGKILL, SEND_SIG_PRIV, victim, PIDTYPE_TGID);
mark_oom_victim(victim);
pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
task_pid_nr(victim), victim->comm, K(victim->mm->total_vm),
@@ -897,7 +897,7 @@ static void __oom_kill_process(struct task_struct *victim)
*/
if (unlikely(p->flags & PF_KTHREAD))
continue;
- do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, PIDTYPE_TGID);
+ do_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_TGID);
}
rcu_read_unlock();
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 8b8b70620bbe7..cbcb8ba51142c 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -732,7 +732,7 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}
-static int apparmor_task_kill(struct task_struct *target, struct siginfo *info,
+static int apparmor_task_kill(struct task_struct *target, struct kernel_siginfo *info,
int sig, const struct cred *cred)
{
struct aa_label *cl, *tl;
diff --git a/security/security.c b/security/security.c
index 736e78da1ab9d..0d504fceda8b2 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1147,7 +1147,7 @@ int security_task_movememory(struct task_struct *p)
return call_int_hook(task_movememory, 0, p);
}
-int security_task_kill(struct task_struct *p, struct siginfo *info,
+int security_task_kill(struct task_struct *p, struct kernel_siginfo *info,
int sig, const struct cred *cred)
{
return call_int_hook(task_kill, 0, p, info, sig, cred);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ad9a9b8e99794..1b500b4c78a72 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4186,7 +4186,7 @@ static int selinux_task_movememory(struct task_struct *p)
PROCESS__SETSCHED, NULL);
}
-static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
+static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
int sig, const struct cred *cred)
{
u32 secid;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 340fc30ad85d7..025de76af1dbf 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2251,7 +2251,7 @@ static int smack_task_movememory(struct task_struct *p)
* Return 0 if write access is permitted
*
*/
-static int smack_task_kill(struct task_struct *p, struct siginfo *info,
+static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info,
int sig, const struct cred *cred)
{
struct smk_audit_info ad;
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index ed162a6c57c59..1a2c3a1c56ce6 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -1450,20 +1450,14 @@ static void invalidate_icache_guest_page(kvm_pfn_t pfn, unsigned long size)
static void kvm_send_hwpoison_signal(unsigned long address,
struct vm_area_struct *vma)
{
- siginfo_t info;
-
- clear_siginfo(&info);
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_MCEERR_AR;
- info.si_addr = (void __user *)address;
+ short lsb;
if (is_vm_hugetlb_page(vma))
- info.si_addr_lsb = huge_page_shift(hstate_vma(vma));
+ lsb = huge_page_shift(hstate_vma(vma));
else
- info.si_addr_lsb = PAGE_SHIFT;
+ lsb = PAGE_SHIFT;
- send_sig_info(SIGBUS, &info, current);
+ send_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, current);
}
static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,