mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 00:40:03 +00:00
x86: ptrace: set TS_COMPAT when 32-bit ptrace sets orig_eax>=0
The 32-bit ptrace syscall on a 64-bit kernel (32-bit debugger on 32-bit task) behaves differently than a native 32-bit kernel. When setting a register state of orig_eax>=0 and eax=-ERESTART* when the debugged task is NOT on its way out of a 32-bit syscall, the task will fail to do the syscall restart logic that it should do. Test case available at http://sources.redhat.com/cgi-bin/cvsweb.cgi/~checkout~/tests/ptrace-tests/tests/erestartsys-trap.c?cvsroot=systemtap This happens because the 32-bit ptrace syscall sets eax=0xffffffff when it sets orig_eax>=0. The resuming task will not sign-extend this for the -ERESTART* check because TS_COMPAT is not set. (So the task thinks it is restarting after a 64-bit syscall, not a 32-bit one.) The fix is to have 32-bit ptrace calls set TS_COMPAT when setting orig_eax>=0. This ensures that the 32-bit syscall restart logic will apply when the child resumes. Signed-off-by: Roland McGrath <roland@redhat.com>
This commit is contained in:
parent
08ff18e299
commit
8cb3ed1393
1 changed files with 13 additions and 1 deletions
|
@ -1111,10 +1111,22 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 value)
|
|||
R32(esi, si);
|
||||
R32(ebp, bp);
|
||||
R32(eax, ax);
|
||||
R32(orig_eax, orig_ax);
|
||||
R32(eip, ip);
|
||||
R32(esp, sp);
|
||||
|
||||
case offsetof(struct user32, regs.orig_eax):
|
||||
/*
|
||||
* A 32-bit debugger setting orig_eax means to restore
|
||||
* the state of the task restarting a 32-bit syscall.
|
||||
* Make sure we interpret the -ERESTART* codes correctly
|
||||
* in case the task is not actually still sitting at the
|
||||
* exit from a 32-bit syscall with TS_COMPAT still set.
|
||||
*/
|
||||
regs->orig_ax = value;
|
||||
if (syscall_get_nr(child, regs) >= 0)
|
||||
task_thread_info(child)->status |= TS_COMPAT;
|
||||
break;
|
||||
|
||||
case offsetof(struct user32, regs.eflags):
|
||||
return set_flags(child, value);
|
||||
|
||||
|
|
Loading…
Reference in a new issue