* [PATCH] MIPS: fix forced successful syscalls
@ 2013-09-30 14:22 Tanguy Bouzeloc
2013-10-02 9:19 ` Ralf Baechle
0 siblings, 1 reply; 4+ messages in thread
From: Tanguy Bouzeloc @ 2013-09-30 14:22 UTC (permalink / raw)
To: ralf; +Cc: linux-mips, Tanguy Bouzeloc
On mips any syscalls who return a value between -MAXERRNO (1133) and
-1, is considered as an error (the error flag is set and return value
is the positive value of the error number).
But some syscalls can return values between -MAXERRNO and -1 like
sys_time and sys_times. In this case the userspace return value is
-return value of the syscall and the error flag set.
This patch add a TIF_NOERROR thread flag which indicates that the
return value of a syscall is always correct.
All ABIs are updated (kernel 32 o32, kernel64 o32, kernel64 n32
and kernel64 n64).
---
arch/mips/include/asm/ptrace.h | 5 +++++
arch/mips/include/asm/thread_info.h | 2 ++
arch/mips/kernel/scall32-o32.S | 14 ++++++++++++++
arch/mips/kernel/scall64-64.S | 14 ++++++++++++++
arch/mips/kernel/scall64-n32.S | 14 ++++++++++++++
arch/mips/kernel/scall64-o32.S | 14 ++++++++++++++
6 files changed, 63 insertions(+)
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index 5e6cd09..51552f2 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -94,6 +94,11 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs)
die(str, regs);
}
+#define force_successful_syscall_return() \
+ do { \
+ set_thread_flag(TIF_NOERROR); \
+ } while(0)
+
#define current_pt_regs() \
({ \
unsigned long sp = (unsigned long)__builtin_frame_address(0); \
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index 61215a3..6764fc1 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -116,6 +116,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */
#define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */
#define TIF_LOAD_WATCH 25 /* If set, load watch registers */
+#define TIF_NOERROR 30 /* Force successful syscall return */
#define TIF_SYSCALL_TRACE 31 /* syscall trace active */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -131,6 +132,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_32BIT_REGS (1<<TIF_32BIT_REGS)
#define _TIF_32BIT_ADDR (1<<TIF_32BIT_ADDR)
#define _TIF_FPUBOUND (1<<TIF_FPUBOUND)
+#define _TIF_NOERROR (1<<TIF_NOERROR)
#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH)
#define _TIF_WORK_SYSCALL_ENTRY (_TIF_NOHZ | _TIF_SYSCALL_TRACE | \
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index e774bb1..4ac30ac 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -58,8 +58,22 @@ stack_done:
jalr t2 # Do The Real Thing (TM)
+ li t0, 0 # no error for negative return ?
+ lw t2, TI_FLAGS($28)
+ li t1, _TIF_NOERROR
+ and t2, t1
+ bnez t2, syscall_ret_noerror
+
li t0, -EMAXERRNO - 1 # error?
sltu t0, t0, v0
+ b syscall_ret_error
+
+syscall_ret_noerror:
+ li t1, ~_TIF_NOERROR # clear TIF_NOERROR
+ and t2, t1
+ sw t2, TI_FLAGS($28)
+
+syscall_ret_error:
sw t0, PT_R7(sp) # set error flag
beqz t0, 1f
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index be6627e..793ba7e 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -61,8 +61,22 @@ NESTED(handle_sys64, PT_SIZE, sp)
jalr t2 # Do The Real Thing (TM)
+ li t0, 0 # no error for negative return ?
+ LONG_L t2, TI_FLAGS($28)
+ li t1, _TIF_NOERROR
+ and t2, t1
+ bnez t2, syscall_ret_noerror
+
li t0, -EMAXERRNO - 1 # error?
sltu t0, t0, v0
+ b syscall_ret_error
+
+syscall_ret_noerror:
+ li t1, ~_TIF_NOERROR # clear TIF_NOERROR
+ and t2, t1
+ LONG_S t2, TI_FLAGS($28)
+
+syscall_ret_error:
sd t0, PT_R7(sp) # set error flag
beqz t0, 1f
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index cab1507..ccac0c6 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -54,8 +54,22 @@ NESTED(handle_sysn32, PT_SIZE, sp)
jalr t2 # Do The Real Thing (TM)
+ li t0, 0 # no error for negative return ?
+ LONG_L t2, TI_FLAGS($28)
+ li t1, _TIF_NOERROR
+ and t2, t1
+ bnez t2, syscall_ret_noerror
+
li t0, -EMAXERRNO - 1 # error?
sltu t0, t0, v0
+ b syscall_ret_error
+
+syscall_ret_noerror:
+ li t1, ~_TIF_NOERROR # clear TIF_NOERROR
+ and t2, t1
+ LONG_S t2, TI_FLAGS($28)
+
+syscall_ret_error:
sd t0, PT_R7(sp) # set error flag
beqz t0, 1f
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 37605dc..b1d3d51 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -88,8 +88,22 @@ NESTED(handle_sys, PT_SIZE, sp)
jalr t2 # Do The Real Thing (TM)
+ li t0, 0 # no error for negative return ?
+ LONG_L t2, TI_FLAGS($28)
+ li t1, _TIF_NOERROR
+ and t2, t1
+ bnez t2, syscall_ret_noerror
+
li t0, -EMAXERRNO - 1 # error?
sltu t0, t0, v0
+ b syscall_ret_error
+
+syscall_ret_noerror:
+ li t1, ~_TIF_NOERROR # clear TIF_NOERROR
+ and t2, t1
+ LONG_S t2, TI_FLAGS($28)
+
+syscall_ret_error:
sd t0, PT_R7(sp) # set error flag
beqz t0, 1f
--
1.8.3.1
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] MIPS: fix forced successful syscalls
2013-09-30 14:22 [PATCH] MIPS: fix forced successful syscalls Tanguy Bouzeloc
@ 2013-10-02 9:19 ` Ralf Baechle
2013-10-03 14:53 ` Tanguy Bouzeloc
0 siblings, 1 reply; 4+ messages in thread
From: Ralf Baechle @ 2013-10-02 9:19 UTC (permalink / raw)
To: Tanguy Bouzeloc; +Cc: linux-mips
On Mon, Sep 30, 2013 at 04:22:49PM +0200, Tanguy Bouzeloc wrote:
> Date: Mon, 30 Sep 2013 16:22:49 +0200
> From: Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
> To: ralf@linux-mips.org
> Cc: linux-mips@linux-mips.org, Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
> Subject: [PATCH] MIPS: fix forced successful syscalls
>
> On mips any syscalls who return a value between -MAXERRNO (1133) and
> -1, is considered as an error (the error flag is set and return value
> is the positive value of the error number).
>
> But some syscalls can return values between -MAXERRNO and -1 like
> sys_time and sys_times. In this case the userspace return value is
> -return value of the syscall and the error flag set.
>
> This patch add a TIF_NOERROR thread flag which indicates that the
> return value of a syscall is always correct.
To my personal embarassment I have to admit that I knew about this since the
day the syscall wrapper was written - but was considering it an acceptable
bug ...
Where it really bits is sigreturn and similar which use the following
stunt:
/*
* Don't let your children do this ...
*/
__asm__ __volatile__(
"move\t$29, %0\n\t"
"j\tsyscall_exit"
:/* no outputs */
:"r" (®s));
/* Unreached */
to keep the syscall return path from tampering with the return value.
The scall*.S part of your patch is clearing TIF_NOERROR using a non-atomic
LW/SW sequence. This needs to be done atomically or the thread's flags
variable might get corrupted. This is complicated by MIPS I, R5900 and
afair some older oddball not-quite MIPS II CPUs lacking LL/SC rsp. LLD/SCD.
Ralf
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] MIPS: fix forced successful syscalls
2013-10-02 9:19 ` Ralf Baechle
@ 2013-10-03 14:53 ` Tanguy Bouzeloc
2013-10-08 7:42 ` Ralf Baechle
0 siblings, 1 reply; 4+ messages in thread
From: Tanguy Bouzeloc @ 2013-10-03 14:53 UTC (permalink / raw)
To: Ralf Baechle; +Cc: linux-mips@linux-mips.org
On 10/02/2013 11:19 AM, Ralf Baechle wrote:
> To my personal embarassment I have to admit that I knew about this since the
> day the syscall wrapper was written - but was considering it an acceptable
> bug ...
>
> Where it really bits is sigreturn and similar which use the following
> stunt:
>
> /*
> * Don't let your children do this ...
> */
> __asm__ __volatile__(
> "move\t$29, %0\n\t"
> "j\tsyscall_exit"
> :/* no outputs */
> :"r" (®s));
> /* Unreached */
>
> to keep the syscall return path from tampering with the return value.
>
> The scall*.S part of your patch is clearing TIF_NOERROR using a non-atomic
> LW/SW sequence. This needs to be done atomically or the thread's flags
> variable might get corrupted. This is complicated by MIPS I, R5900 and
> afair some older oddball not-quite MIPS II CPUs lacking LL/SC rsp. LLD/SCD.
>
> Ralf
>
I discover the issue when changing the HZ of the kernel to 100HZ, in
this case the jiffies returned to the userland are the same as the
kernel ticks and it'll wrap after 5 minutes of uptime. With kernel HZ at
250 or 1000H it'll make happen the ticks wrap after 230~260j.
Unfortunately programs relying on ticks (they shouldn't but that
happens) have unpredictable behavior for 11.3s before the wrap.
I can update the patch in order to access atomically the thread flags,
the point is ... it'll make the kernel incompatible with old hardware.
Regards,
Tanguy.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] MIPS: fix forced successful syscalls
2013-10-03 14:53 ` Tanguy Bouzeloc
@ 2013-10-08 7:42 ` Ralf Baechle
0 siblings, 0 replies; 4+ messages in thread
From: Ralf Baechle @ 2013-10-08 7:42 UTC (permalink / raw)
To: Tanguy Bouzeloc; +Cc: linux-mips@linux-mips.org
On Thu, Oct 03, 2013 at 04:53:31PM +0200, Tanguy Bouzeloc wrote:
> On 10/02/2013 11:19 AM, Ralf Baechle wrote:
> >To my personal embarassment I have to admit that I knew about this since the
> >day the syscall wrapper was written - but was considering it an acceptable
> >bug ...
> >
> >Where it really bits is sigreturn and similar which use the following
> >stunt:
> >
> > /*
> > * Don't let your children do this ...
> > */
> > __asm__ __volatile__(
> > "move\t$29, %0\n\t"
> > "j\tsyscall_exit"
> > :/* no outputs */
> > :"r" (®s));
> > /* Unreached */
> >
> >to keep the syscall return path from tampering with the return value.
> >
> >The scall*.S part of your patch is clearing TIF_NOERROR using a non-atomic
> >LW/SW sequence. This needs to be done atomically or the thread's flags
> >variable might get corrupted. This is complicated by MIPS I, R5900 and
> >afair some older oddball not-quite MIPS II CPUs lacking LL/SC rsp. LLD/SCD.
> >
> > Ralf
> >
>
> I discover the issue when changing the HZ of the kernel to 100HZ, in
> this case the jiffies returned to the userland are the same as the
> kernel ticks and it'll wrap after 5 minutes of uptime. With kernel
> HZ at 250 or 1000H it'll make happen the ticks wrap after 230~260j.
>
> Unfortunately programs relying on ticks (they shouldn't but that
> happens) have unpredictable behavior for 11.3s before the wrap.
>
> I can update the patch in order to access atomically the thread
> flags, the point is ... it'll make the kernel incompatible with old
> hardware.
The price to pay: an ifdef ...
#include <asm/sgidefs.H>
...
#if (_MIPS_ISA > _MIPS_ISA_MIPS1)
... LL/SC code goes here
#else
... LL/SC-less code goes here
#endif
But I'm wondering if we can move this hopefully relativly rare special
case into do_notify_resume() and handle it in plain C there.
Ralf
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-10-08 7:42 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-30 14:22 [PATCH] MIPS: fix forced successful syscalls Tanguy Bouzeloc
2013-10-02 9:19 ` Ralf Baechle
2013-10-03 14:53 ` Tanguy Bouzeloc
2013-10-08 7:42 ` Ralf Baechle
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.