mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
![Linus Torvalds](/assets/img/avatar_default.png)
Pull force_sig() argument change from Eric Biederman: "A source of error over the years has been that force_sig has taken a task parameter when it is only safe to use force_sig with the current task. The force_sig function is built for delivering synchronous signals such as SIGSEGV where the userspace application caused a synchronous fault (such as a page fault) and the kernel responded with a signal. Because the name force_sig does not make this clear, and because the force_sig takes a task parameter the function force_sig has been abused for sending other kinds of signals over the years. Slowly those have been fixed when the oopses have been tracked down. This set of changes fixes the remaining abusers of force_sig and carefully rips out the task parameter from force_sig and friends making this kind of error almost impossible in the future" * 'siginfo-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (27 commits) signal/x86: Move tsk inside of CONFIG_MEMORY_FAILURE in do_sigbus signal: Remove the signal number and task parameters from force_sig_info signal: Factor force_sig_info_to_task out of force_sig_info signal: Generate the siginfo in force_sig signal: Move the computation of force into send_signal and correct it. signal: Properly set TRACE_SIGNAL_LOSE_INFO in __send_signal signal: Remove the task parameter from force_sig_fault signal: Use force_sig_fault_to_task for the two calls that don't deliver to current signal: Explicitly call force_sig_fault on current signal/unicore32: Remove tsk parameter from __do_user_fault signal/arm: Remove tsk parameter from __do_user_fault signal/arm: Remove tsk parameter from ptrace_break signal/nds32: Remove tsk parameter from send_sigtrap signal/riscv: Remove tsk parameter from do_trap signal/sh: Remove tsk parameter from force_sig_info_fault signal/um: Remove task parameter from send_sigtrap signal/x86: Remove task parameter from send_sigtrap signal: Remove task parameter from force_sig_mceerr signal: Remove task parameter from force_sig signal: Remove task parameter from force_sigsegv ...
407 lines
14 KiB
C
407 lines
14 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Port on Texas Instruments TMS320C6x architecture
|
|
*
|
|
* Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
|
|
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/sched/debug.h>
|
|
#include <linux/bug.h>
|
|
|
|
#include <asm/soc.h>
|
|
#include <asm/special_insns.h>
|
|
#include <asm/traps.h>
|
|
|
|
int (*c6x_nmi_handler)(struct pt_regs *regs);
|
|
|
|
void __init trap_init(void)
|
|
{
|
|
ack_exception(EXCEPT_TYPE_NXF);
|
|
ack_exception(EXCEPT_TYPE_EXC);
|
|
ack_exception(EXCEPT_TYPE_IXF);
|
|
ack_exception(EXCEPT_TYPE_SXF);
|
|
enable_exception();
|
|
}
|
|
|
|
void show_regs(struct pt_regs *regs)
|
|
{
|
|
pr_err("\n");
|
|
show_regs_print_info(KERN_ERR);
|
|
pr_err("PC: %08lx SP: %08lx\n", regs->pc, regs->sp);
|
|
pr_err("Status: %08lx ORIG_A4: %08lx\n", regs->csr, regs->orig_a4);
|
|
pr_err("A0: %08lx B0: %08lx\n", regs->a0, regs->b0);
|
|
pr_err("A1: %08lx B1: %08lx\n", regs->a1, regs->b1);
|
|
pr_err("A2: %08lx B2: %08lx\n", regs->a2, regs->b2);
|
|
pr_err("A3: %08lx B3: %08lx\n", regs->a3, regs->b3);
|
|
pr_err("A4: %08lx B4: %08lx\n", regs->a4, regs->b4);
|
|
pr_err("A5: %08lx B5: %08lx\n", regs->a5, regs->b5);
|
|
pr_err("A6: %08lx B6: %08lx\n", regs->a6, regs->b6);
|
|
pr_err("A7: %08lx B7: %08lx\n", regs->a7, regs->b7);
|
|
pr_err("A8: %08lx B8: %08lx\n", regs->a8, regs->b8);
|
|
pr_err("A9: %08lx B9: %08lx\n", regs->a9, regs->b9);
|
|
pr_err("A10: %08lx B10: %08lx\n", regs->a10, regs->b10);
|
|
pr_err("A11: %08lx B11: %08lx\n", regs->a11, regs->b11);
|
|
pr_err("A12: %08lx B12: %08lx\n", regs->a12, regs->b12);
|
|
pr_err("A13: %08lx B13: %08lx\n", regs->a13, regs->b13);
|
|
pr_err("A14: %08lx B14: %08lx\n", regs->a14, regs->dp);
|
|
pr_err("A15: %08lx B15: %08lx\n", regs->a15, regs->sp);
|
|
pr_err("A16: %08lx B16: %08lx\n", regs->a16, regs->b16);
|
|
pr_err("A17: %08lx B17: %08lx\n", regs->a17, regs->b17);
|
|
pr_err("A18: %08lx B18: %08lx\n", regs->a18, regs->b18);
|
|
pr_err("A19: %08lx B19: %08lx\n", regs->a19, regs->b19);
|
|
pr_err("A20: %08lx B20: %08lx\n", regs->a20, regs->b20);
|
|
pr_err("A21: %08lx B21: %08lx\n", regs->a21, regs->b21);
|
|
pr_err("A22: %08lx B22: %08lx\n", regs->a22, regs->b22);
|
|
pr_err("A23: %08lx B23: %08lx\n", regs->a23, regs->b23);
|
|
pr_err("A24: %08lx B24: %08lx\n", regs->a24, regs->b24);
|
|
pr_err("A25: %08lx B25: %08lx\n", regs->a25, regs->b25);
|
|
pr_err("A26: %08lx B26: %08lx\n", regs->a26, regs->b26);
|
|
pr_err("A27: %08lx B27: %08lx\n", regs->a27, regs->b27);
|
|
pr_err("A28: %08lx B28: %08lx\n", regs->a28, regs->b28);
|
|
pr_err("A29: %08lx B29: %08lx\n", regs->a29, regs->b29);
|
|
pr_err("A30: %08lx B30: %08lx\n", regs->a30, regs->b30);
|
|
pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31);
|
|
}
|
|
|
|
void die(char *str, struct pt_regs *fp, int nr)
|
|
{
|
|
console_verbose();
|
|
pr_err("%s: %08x\n", str, nr);
|
|
show_regs(fp);
|
|
|
|
pr_err("Process %s (pid: %d, stackpage=%08lx)\n",
|
|
current->comm, current->pid, (PAGE_SIZE +
|
|
(unsigned long) current));
|
|
|
|
dump_stack();
|
|
while (1)
|
|
;
|
|
}
|
|
|
|
static void die_if_kernel(char *str, struct pt_regs *fp, int nr)
|
|
{
|
|
if (user_mode(fp))
|
|
return;
|
|
|
|
die(str, fp, nr);
|
|
}
|
|
|
|
|
|
/* Internal exceptions */
|
|
static struct exception_info iexcept_table[10] = {
|
|
{ "Oops - instruction fetch", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - fetch packet", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - execute packet", SIGILL, ILL_ILLOPC },
|
|
{ "Oops - undefined instruction", SIGILL, ILL_ILLOPC },
|
|
{ "Oops - resource conflict", SIGILL, ILL_ILLOPC },
|
|
{ "Oops - resource access", SIGILL, ILL_PRVREG },
|
|
{ "Oops - privilege", SIGILL, ILL_PRVOPC },
|
|
{ "Oops - loops buffer", SIGILL, ILL_ILLOPC },
|
|
{ "Oops - software exception", SIGILL, ILL_ILLTRP },
|
|
{ "Oops - unknown exception", SIGILL, ILL_ILLOPC }
|
|
};
|
|
|
|
/* External exceptions */
|
|
static struct exception_info eexcept_table[128] = {
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
|
|
{ "Oops - CPU memory protection fault", SIGSEGV, SEGV_ACCERR },
|
|
{ "Oops - CPU memory protection fault in L1P", SIGSEGV, SEGV_ACCERR },
|
|
{ "Oops - DMA memory protection fault in L1P", SIGSEGV, SEGV_ACCERR },
|
|
{ "Oops - CPU memory protection fault in L1D", SIGSEGV, SEGV_ACCERR },
|
|
{ "Oops - DMA memory protection fault in L1D", SIGSEGV, SEGV_ACCERR },
|
|
{ "Oops - CPU memory protection fault in L2", SIGSEGV, SEGV_ACCERR },
|
|
{ "Oops - DMA memory protection fault in L2", SIGSEGV, SEGV_ACCERR },
|
|
{ "Oops - EMC CPU memory protection fault", SIGSEGV, SEGV_ACCERR },
|
|
{ "Oops - EMC bus error", SIGBUS, BUS_ADRERR }
|
|
};
|
|
|
|
static void do_trap(struct exception_info *except_info, struct pt_regs *regs)
|
|
{
|
|
unsigned long addr = instruction_pointer(regs);
|
|
|
|
if (except_info->code != TRAP_BRKPT)
|
|
pr_err("TRAP: %s PC[0x%lx] signo[%d] code[%d]\n",
|
|
except_info->kernel_str, regs->pc,
|
|
except_info->signo, except_info->code);
|
|
|
|
die_if_kernel(except_info->kernel_str, regs, addr);
|
|
|
|
force_sig_fault(except_info->signo, except_info->code,
|
|
(void __user *)addr);
|
|
}
|
|
|
|
/*
|
|
* Process an internal exception (non maskable)
|
|
*/
|
|
static int process_iexcept(struct pt_regs *regs)
|
|
{
|
|
unsigned int iexcept_report = get_iexcept();
|
|
unsigned int iexcept_num;
|
|
|
|
ack_exception(EXCEPT_TYPE_IXF);
|
|
|
|
pr_err("IEXCEPT: PC[0x%lx]\n", regs->pc);
|
|
|
|
while (iexcept_report) {
|
|
iexcept_num = __ffs(iexcept_report);
|
|
iexcept_report &= ~(1 << iexcept_num);
|
|
set_iexcept(iexcept_report);
|
|
if (*(unsigned int *)regs->pc == BKPT_OPCODE) {
|
|
/* This is a breakpoint */
|
|
struct exception_info bkpt_exception = {
|
|
"Oops - undefined instruction",
|
|
SIGTRAP, TRAP_BRKPT
|
|
};
|
|
do_trap(&bkpt_exception, regs);
|
|
iexcept_report &= ~(0xFF);
|
|
set_iexcept(iexcept_report);
|
|
continue;
|
|
}
|
|
|
|
do_trap(&iexcept_table[iexcept_num], regs);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Process an external exception (maskable)
|
|
*/
|
|
static void process_eexcept(struct pt_regs *regs)
|
|
{
|
|
int evt;
|
|
|
|
pr_err("EEXCEPT: PC[0x%lx]\n", regs->pc);
|
|
|
|
while ((evt = soc_get_exception()) >= 0)
|
|
do_trap(&eexcept_table[evt], regs);
|
|
|
|
ack_exception(EXCEPT_TYPE_EXC);
|
|
}
|
|
|
|
/*
|
|
* Main exception processing
|
|
*/
|
|
asmlinkage int process_exception(struct pt_regs *regs)
|
|
{
|
|
unsigned int type;
|
|
unsigned int type_num;
|
|
unsigned int ie_num = 9; /* default is unknown exception */
|
|
|
|
while ((type = get_except_type()) != 0) {
|
|
type_num = fls(type) - 1;
|
|
|
|
switch (type_num) {
|
|
case EXCEPT_TYPE_NXF:
|
|
ack_exception(EXCEPT_TYPE_NXF);
|
|
if (c6x_nmi_handler)
|
|
(c6x_nmi_handler)(regs);
|
|
else
|
|
pr_alert("NMI interrupt!\n");
|
|
break;
|
|
|
|
case EXCEPT_TYPE_IXF:
|
|
if (process_iexcept(regs))
|
|
return 1;
|
|
break;
|
|
|
|
case EXCEPT_TYPE_EXC:
|
|
process_eexcept(regs);
|
|
break;
|
|
|
|
case EXCEPT_TYPE_SXF:
|
|
ie_num = 8;
|
|
default:
|
|
ack_exception(type_num);
|
|
do_trap(&iexcept_table[ie_num], regs);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int kstack_depth_to_print = 48;
|
|
|
|
static void show_trace(unsigned long *stack, unsigned long *endstack)
|
|
{
|
|
unsigned long addr;
|
|
int i;
|
|
|
|
pr_debug("Call trace:");
|
|
i = 0;
|
|
while (stack + 1 <= endstack) {
|
|
addr = *stack++;
|
|
/*
|
|
* If the address is either in the text segment of the
|
|
* kernel, or in the region which contains vmalloc'ed
|
|
* memory, it *may* be the address of a calling
|
|
* routine; if so, print it so that someone tracing
|
|
* down the cause of the crash will be able to figure
|
|
* out the call path that was taken.
|
|
*/
|
|
if (__kernel_text_address(addr)) {
|
|
#ifndef CONFIG_KALLSYMS
|
|
if (i % 5 == 0)
|
|
pr_debug("\n ");
|
|
#endif
|
|
pr_debug(" [<%08lx>] %pS\n", addr, (void *)addr);
|
|
i++;
|
|
}
|
|
}
|
|
pr_debug("\n");
|
|
}
|
|
|
|
void show_stack(struct task_struct *task, unsigned long *stack)
|
|
{
|
|
unsigned long *p, *endstack;
|
|
int i;
|
|
|
|
if (!stack) {
|
|
if (task && task != current)
|
|
/* We know this is a kernel stack,
|
|
so this is the start/end */
|
|
stack = (unsigned long *)thread_saved_ksp(task);
|
|
else
|
|
stack = (unsigned long *)&stack;
|
|
}
|
|
endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1)
|
|
& -THREAD_SIZE);
|
|
|
|
pr_debug("Stack from %08lx:", (unsigned long)stack);
|
|
for (i = 0, p = stack; i < kstack_depth_to_print; i++) {
|
|
if (p + 1 > endstack)
|
|
break;
|
|
if (i % 8 == 0)
|
|
pr_cont("\n ");
|
|
pr_cont(" %08lx", *p++);
|
|
}
|
|
pr_cont("\n");
|
|
show_trace(stack, endstack);
|
|
}
|
|
|
|
int is_valid_bugaddr(unsigned long addr)
|
|
{
|
|
return __kernel_text_address(addr);
|
|
}
|