From: Jeff Dike 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: Bodo Stroesser Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton --- 25-akpm/arch/um/kernel/skas/process.c | 6 +++++- 25-akpm/arch/um/kernel/tt/tracer.c | 5 ++++- 25-akpm/arch/um/sys-i386/signal.c | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff -puN arch/um/kernel/skas/process.c~uml-system-call-restart-fixes arch/um/kernel/skas/process.c --- 25/arch/um/kernel/skas/process.c~uml-system-call-restart-fixes Fri Dec 3 13:50:36 2004 +++ 25-akpm/arch/um/kernel/skas/process.c Fri Dec 3 13:50:36 2004 @@ -63,6 +63,7 @@ static void handle_trap(int pid, union u { int err, status; + /* Mark this as a syscall */ UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs); if (!local_using_sysemu) @@ -160,6 +161,7 @@ void userspace(union uml_pt_regs *regs) regs->skas.is_user = 1; save_registers(regs); + UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ @@ -170,7 +172,6 @@ void userspace(union uml_pt_regs *regs) handle_trap(pid, regs, local_using_sysemu); break; case SIGTRAP: - UPT_SYSCALL_NR(regs) = -1; relay_signal(SIGTRAP, regs); break; case SIGIO: @@ -186,6 +187,9 @@ void userspace(union uml_pt_regs *regs) "%d\n", WSTOPSIG(status)); } interrupt_end(); + + /* Avoid -ERESTARTSYS handling in host */ + PT_SYSCALL_NR(regs->skas.regs) = -1; } restore_registers(regs); diff -puN arch/um/kernel/tt/tracer.c~uml-system-call-restart-fixes arch/um/kernel/tt/tracer.c --- 25/arch/um/kernel/tt/tracer.c~uml-system-call-restart-fixes Fri Dec 3 13:50:36 2004 +++ 25-akpm/arch/um/kernel/tt/tracer.c Fri Dec 3 13:50:36 2004 @@ -303,6 +303,10 @@ int tracer(int (*init_proc)(void *), voi tracing = is_tracing(task); old_tracing = tracing; + /* Assume: no syscall, when coming from user */ + if ( tracing ) + do_sigtrap(task); + local_using_sysemu = get_using_sysemu(); pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL; @@ -354,7 +358,6 @@ int tracer(int (*init_proc)(void *), voi continue; } tracing = 0; - do_sigtrap(task); break; case SIGPROF: if(tracing) sig = 0; diff -puN arch/um/sys-i386/signal.c~uml-system-call-restart-fixes arch/um/sys-i386/signal.c --- 25/arch/um/sys-i386/signal.c~uml-system-call-restart-fixes Fri Dec 3 13:50:36 2004 +++ 25-akpm/arch/um/sys-i386/signal.c Fri Dec 3 13:50:36 2004 @@ -324,6 +324,8 @@ long sys_sigreturn(struct pt_regs regs) if(copy_sc_from_user(¤t->thread.regs, sc)) goto segfault; + /* Avoid ERESTART handling */ + PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); segfault: @@ -352,6 +354,8 @@ long sys_rt_sigreturn(struct pt_regs reg if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) goto segfault; + /* Avoid ERESTART handling */ + PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); segfault: _