x86: Introduce TS_COMPAT_RESTART to fix get_nr_restart_syscall()
authorOleg Nesterov <oleg@redhat.com>
Mon, 1 Feb 2021 17:47:09 +0000 (18:47 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 16 Mar 2021 21:13:11 +0000 (22:13 +0100)
commit8c150ba2fb5995c84a7a43848250d444a3329a7d
tree711ea8a4125668f0749c8f0692a258585dec00a0
parent66c1b6d74cd7035e85c426f0af4aede19e805c8a
x86: Introduce TS_COMPAT_RESTART to fix get_nr_restart_syscall()

The comment in get_nr_restart_syscall() says:

 * 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.

Yes, but if not in a syscall then the

status & (TS_COMPAT|TS_I386_REGS_POKED)

check below can't really help:

- TS_COMPAT can't be set

- TS_I386_REGS_POKED is only set if regs->orig_ax was changed by
  32bit debugger; and even in this case get_nr_restart_syscall()
  is only correct if the tracee is 32bit too.

Suppose that a 64bit debugger plays with a 32bit tracee and

* Tracee calls sleep(2) // TS_COMPAT is set
* User interrupts the tracee by CTRL-C after 1 sec and does
  "(gdb) call func()"
* gdb saves the regs by PTRACE_GETREGS
* does PTRACE_SETREGS to set %rip='func' and %orig_rax=-1
* PTRACE_CONT // TS_COMPAT is cleared
* func() hits int3.
* Debugger catches SIGTRAP.
* Restore original regs by PTRACE_SETREGS.
* PTRACE_CONT

get_nr_restart_syscall() wrongly returns __NR_restart_syscall==219, the
tracee calls ia32_sys_call_table[219] == sys_madvise.

Add the sticky TS_COMPAT_RESTART flag which survives after return to user
mode. It's going to be removed in the next step again by storing the
information in the restart block. As a further cleanup it might be possible
to remove also TS_I386_REGS_POKED with that.

Test-case:

  $ cvs -d :pserver:anoncvs:anoncvs@sourceware.org:/cvs/systemtap co ptrace-tests
  $ gcc -o erestartsys-trap-debuggee ptrace-tests/tests/erestartsys-trap-debuggee.c --m32
  $ gcc -o erestartsys-trap-debugger ptrace-tests/tests/erestartsys-trap-debugger.c -lutil
  $ ./erestartsys-trap-debugger
  Unexpected: retval 1, errno 22
  erestartsys-trap-debugger: ptrace-tests/tests/erestartsys-trap-debugger.c:421

Fixes: 609c19a385c8 ("x86/ptrace: Stop setting TS_COMPAT in ptrace code")
Reported-by: Jan Kratochvil <jan.kratochvil@redhat.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20210201174709.GA17895@redhat.com
arch/x86/include/asm/thread_info.h
arch/x86/kernel/signal.c