|
@@ -760,8 +760,30 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
|
|
|
|
|
|
static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs)
|
|
|
{
|
|
|
-#ifdef CONFIG_X86_64
|
|
|
- if (in_ia32_syscall())
|
|
|
+ /*
|
|
|
+ * This function is fundamentally broken as currently
|
|
|
+ * implemented.
|
|
|
+ *
|
|
|
+ * The idea is that we want to trigger a call to the
|
|
|
+ * restart_block() syscall and that we want in_ia32_syscall(),
|
|
|
+ * in_x32_syscall(), etc. to match whatever they were in the
|
|
|
+ * syscall being restarted. We assume that the syscall
|
|
|
+ * instruction at (regs->ip - 2) matches whatever syscall
|
|
|
+ * instruction we used to enter in the first place.
|
|
|
+ *
|
|
|
+ * The problem is that we can get here when ptrace pokes
|
|
|
+ * syscall-like values into regs even if we're not in a syscall
|
|
|
+ * at all.
|
|
|
+ *
|
|
|
+ * For now, we maintain historical behavior and guess based on
|
|
|
+ * stored state. We could do better by saving the actual
|
|
|
+ * syscall arch in restart_block or (with caveats on x32) by
|
|
|
+ * checking if regs->ip points to 'int $0x80'. The current
|
|
|
+ * behavior is incorrect if a tracer has a different bitness
|
|
|
+ * than the tracee.
|
|
|
+ */
|
|
|
+#ifdef CONFIG_IA32_EMULATION
|
|
|
+ if (current_thread_info()->status & (TS_COMPAT|TS_I386_REGS_POKED))
|
|
|
return __NR_ia32_restart_syscall;
|
|
|
#endif
|
|
|
#ifdef CONFIG_X86_X32_ABI
|