Commit a385187c authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds

[PATCH] uml: system call restart fixes

From: Bodo Stroesser

The implementation of sys_sigreturn() and sys_rt_sigreturn() in UML
must be changed.
This is necessary, since the return value of sys_*_sigreturn()
is the value of eax in the thread, that was interrupted by the
signal handler. If accidentaly eax contains -ERESTART_*, orig_eax
*must* be -1 to avoid syscall restart processing in kern_do_signal().
If orig_eax is >=0, eip might be lowered by 2, the process will fail.
In UML PT_REGS_SYSCALL_NR() or UPT_SYSCALL_NR() have to be used
instead of orig_eax.

While writing and testing an exploit for this, I saw that for most
interrupts, the syscall number is undefined. So even on a return from
interrupt a wrong syscall restart handling could happen.

And also: UML resumes a process with ptrace(PTRACE_SYSCALL/SYSEMU/SINGLESTEP
when a syscall in UML in SKAS mode has been processed. But since there
is a valid syscall number in the host's orig_eax, the host could do
a wrong syscall restarting if the syscall in UML was a sigreturn() returning
-ERESTART* To avoid this, in SKAS -1 should be written to regs.orig_eax
before restore_registers().
Signed-off-by: default avatarBodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: default avatarPaolo 'Blaisorblade' Giarrusso <blaisorblade_spam@yahoo.it>
Signed-off-by: default avatarJeff Dike <jdike@addtoit.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 38befeba
...@@ -63,6 +63,7 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu ...@@ -63,6 +63,7 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
{ {
int err, status; int err, status;
/* Mark this as a syscall */
UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs); UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs);
if (!local_using_sysemu) if (!local_using_sysemu)
...@@ -160,6 +161,7 @@ void userspace(union uml_pt_regs *regs) ...@@ -160,6 +161,7 @@ void userspace(union uml_pt_regs *regs)
regs->skas.is_user = 1; regs->skas.is_user = 1;
save_registers(regs); save_registers(regs);
UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
if(WIFSTOPPED(status)){ if(WIFSTOPPED(status)){
switch(WSTOPSIG(status)){ switch(WSTOPSIG(status)){
...@@ -170,7 +172,6 @@ void userspace(union uml_pt_regs *regs) ...@@ -170,7 +172,6 @@ void userspace(union uml_pt_regs *regs)
handle_trap(pid, regs, local_using_sysemu); handle_trap(pid, regs, local_using_sysemu);
break; break;
case SIGTRAP: case SIGTRAP:
UPT_SYSCALL_NR(regs) = -1;
relay_signal(SIGTRAP, regs); relay_signal(SIGTRAP, regs);
break; break;
case SIGIO: case SIGIO:
...@@ -186,6 +187,9 @@ void userspace(union uml_pt_regs *regs) ...@@ -186,6 +187,9 @@ void userspace(union uml_pt_regs *regs)
"%d\n", WSTOPSIG(status)); "%d\n", WSTOPSIG(status));
} }
interrupt_end(); interrupt_end();
/* Avoid -ERESTARTSYS handling in host */
PT_SYSCALL_NR(regs->skas.regs) = -1;
} }
restore_registers(regs); restore_registers(regs);
......
...@@ -303,6 +303,10 @@ int tracer(int (*init_proc)(void *), void *sp) ...@@ -303,6 +303,10 @@ int tracer(int (*init_proc)(void *), void *sp)
tracing = is_tracing(task); tracing = is_tracing(task);
old_tracing = tracing; old_tracing = tracing;
/* Assume: no syscall, when coming from user */
if ( tracing )
do_sigtrap(task);
local_using_sysemu = get_using_sysemu(); local_using_sysemu = get_using_sysemu();
pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL; pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL;
...@@ -354,7 +358,6 @@ int tracer(int (*init_proc)(void *), void *sp) ...@@ -354,7 +358,6 @@ int tracer(int (*init_proc)(void *), void *sp)
continue; continue;
} }
tracing = 0; tracing = 0;
do_sigtrap(task);
break; break;
case SIGPROF: case SIGPROF:
if(tracing) sig = 0; if(tracing) sig = 0;
......
...@@ -324,6 +324,8 @@ long sys_sigreturn(struct pt_regs regs) ...@@ -324,6 +324,8 @@ long sys_sigreturn(struct pt_regs regs)
if(copy_sc_from_user(&current->thread.regs, sc)) if(copy_sc_from_user(&current->thread.regs, sc))
goto segfault; goto segfault;
/* Avoid ERESTART handling */
PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
return(PT_REGS_SYSCALL_RET(&current->thread.regs)); return(PT_REGS_SYSCALL_RET(&current->thread.regs));
segfault: segfault:
...@@ -352,6 +354,8 @@ long sys_rt_sigreturn(struct pt_regs regs) ...@@ -352,6 +354,8 @@ long sys_rt_sigreturn(struct pt_regs regs)
if(copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext)) if(copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext))
goto segfault; goto segfault;
/* Avoid ERESTART handling */
PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
return(PT_REGS_SYSCALL_RET(&current->thread.regs)); return(PT_REGS_SYSCALL_RET(&current->thread.regs));
segfault: segfault:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment