This seems to be a minimal reproducer: https://481768.bugs.gentoo.org/attachment.cgi?id=361728
That's a REALLY nasty bug! I see at least two issues here: A Linux kernel bug and a gdb (userspace) bug. The kernel bug is, that a userspace process (running gdb) is able to crash the machine. The attached patch does fix the crashes by preventing userspace to change IAOQ values to point to the gateway page. This is what made the kernel crash, which probably happened, when the kernel tried to switch_to() the process. I'm still trying to figure out if there is a better patch, e.g. in the switch_to() function or similar. So, I don't think it's the final patch. Anyway, this patch can help to figure out what's else going wrong. Then, the second issue is: In gdb this crashes the machine: "set tp = { 0,0 }". Correct would be: "set *tp = { 0,0 }", which does NOT crash the kernel and works correctly. So, for the first test it seems that gdb tries to create a temporary variable on the stack for "tp" in the user process. For that gdb analyzes the code and thus somehow starts executing the attached process. I think some gdb-expert might be able to fix this, esp. since gdb now prints: : The program being debugged stopped while in a function called from GDB. : Evaluation of the expression containing the function : (malloc) will be abandoned. : When the function is done executing, GDB will silently stop. Maybe gdb tries to call the "malloc" function to allocate memory? gdb uses ptrace() to control the attached process. So, adding a printk("PTRACE_REQUEST_PARISC req=0x%lx addr=0x%lx data=0x%lx\n", request, addr, data); to arch_ptrace() in arch/parisc/kernel/ptrace.c helps to debug what gdb does. Helge
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index a3d2fb4e6dd2..1b1af8a6508f 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -167,6 +175,14 @@ long arch_ptrace(struct task_struct *child, long request, if ((addr & (sizeof(unsigned long)-1)) || addr >= sizeof(struct pt_regs)) break; + /* Do not allow userspace to set IAOQ to gateway page. */ + if (addr == PT_IAOQ0 || addr == PT_IAOQ1) { + if (data < GATEWAY_PAGE_SIZE) { + ret = 0; // return sucess to not disturb gdb + // printk("UGH!!!!!!!!!!!!!!!!!!!!\n"); + break; + } + } if ((addr >= PT_GR1 && addr <= PT_GR31) || addr == PT_IAOQ0 || addr == PT_IAOQ1 || (addr >= PT_FR0 && addr <= PT_FR31 + 4) || @@ -281,6 +297,14 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, addr = translate_usr_offset(addr); if (addr >= sizeof(struct pt_regs)) break; + /* Do not allow userspace to set IAOQ to gateway page. */ + if (addr == PT_IAOQ0 || addr == PT_IAOQ1) { + if (data < GATEWAY_PAGE_SIZE) { + ret = 0; // return sucess to not disturb gdb + // printk("UGH!!!!!!!!!!!!!!!!!!!!\n"); + break; + } + } if (addr >= PT_FR0 && addr <= PT_FR31 + 4) { /* Special case, fp regs are 64 bits anyway */ *(__u64 *) ((char *) task_regs(child) + addr) = data;