2018-04-17 14:08:36

by Matt Redfearn

[permalink] [raw]
Subject: [PATCH 1/3] MIPS: memset.S: Fix clobber of v1 in last_fixup

The label .Llast_fixup\@ is jumped to on page fault within the final
byte set loop of memset (on < MIPSR6 architectures). For some reason, in
this fault handler, the v1 register is randomly set to a2 & STORMASK.
This clobbers v1 for the calling function. This can be observed with the
following test code:

static int __init __attribute__((optimize("O0"))) test_clear_user(void)
{
register int t asm("v1");
char *test;
int j, k;

pr_info("\n\n\nTesting clear_user\n");
test = vmalloc(PAGE_SIZE);

for (j = 256; j < 512; j++) {
t = 0xa5a5a5a5;
if ((k = clear_user(test + PAGE_SIZE - 256, j)) != j - 256) {
pr_err("clear_user (%px %d) returned %d\n", test + PAGE_SIZE - 256, j, k);
}
if (t != 0xa5a5a5a5) {
pr_err("v1 was clobbered to 0x%x!\n", t);
}
}

return 0;
}
late_initcall(test_clear_user);

Which demonstrates that v1 is indeed clobbered (MIPS64):

Testing clear_user
v1 was clobbered to 0x1!
v1 was clobbered to 0x2!
v1 was clobbered to 0x3!
v1 was clobbered to 0x4!
v1 was clobbered to 0x5!
v1 was clobbered to 0x6!
v1 was clobbered to 0x7!

Since the number of bytes that could not be set is already contained in
a2, the andi placing a value in v1 is not necessary and actively
harmful in clobbering v1.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: [email protected]
Reported-by: James Hogan <[email protected]>
Signed-off-by: Matt Redfearn <[email protected]>
---

arch/mips/lib/memset.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
index fa3bec269331..84e91f4fdf53 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/memset.S
@@ -258,7 +258,7 @@

.Llast_fixup\@:
jr ra
- andi v1, a2, STORMASK
+ nop

.Lsmall_fixup\@:
PTR_SUBU a2, t1, a0
--
2.7.4



2018-04-17 14:09:03

by Matt Redfearn

[permalink] [raw]
Subject: [PATCH 2/3] MIPS: uaccess: Add micromips clobbers to bzero invocation

The micromips implementation of bzero additionally clobbers registers t7
& t8. Specify this in the clobbers list when invoking bzero.

Reported-by: James Hogan <[email protected]>
Fixes: 26c5e07d1478 ("MIPS: microMIPS: Optimise 'memset' core library function.")
Cc: [email protected]
Signed-off-by: Matt Redfearn <[email protected]>
---

arch/mips/include/asm/uaccess.h | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index b71306947290..06629011a434 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -654,6 +654,13 @@ __clear_user(void __user *addr, __kernel_size_t size)
{
__kernel_size_t res;

+#ifdef CONFIG_CPU_MICROMIPS
+/* micromips memset / bzero also clobbers t7 & t8 */
+#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$15", "$24", "$31"
+#else
+#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$31"
+#endif /* CONFIG_CPU_MICROMIPS */
+
if (eva_kernel_access()) {
__asm__ __volatile__(
"move\t$4, %1\n\t"
@@ -663,7 +670,7 @@ __clear_user(void __user *addr, __kernel_size_t size)
"move\t%0, $6"
: "=r" (res)
: "r" (addr), "r" (size)
- : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+ : bzero_clobbers);
} else {
might_fault();
__asm__ __volatile__(
@@ -674,7 +681,7 @@ __clear_user(void __user *addr, __kernel_size_t size)
"move\t%0, $6"
: "=r" (res)
: "r" (addr), "r" (size)
- : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+ : bzero_clobbers);
}

return res;
--
2.7.4


2018-04-17 14:09:19

by Matt Redfearn

[permalink] [raw]
Subject: [PATCH 3/3] MIPS: memset.S: Reinstate delay slot indentation

Assembly language within the MIPS kernel conventionally indents
instructions which are in a branch delay slot to make them easier to
see. Commit 8483b14aaa81 ("MIPS: lib: memset: Whitespace fixes") rather
inexplicably removed all of these indentations from memset.S. Reinstate
the convention for all instructions in a branch delay slot. This
effectively reverts the above commit, plus other locations introduced
with MIPSR6 support.

Signed-off-by: Matt Redfearn <[email protected]>
---

arch/mips/lib/memset.S | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
index 84e91f4fdf53..085cc86f624f 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/memset.S
@@ -95,7 +95,7 @@

sltiu t0, a2, STORSIZE /* very small region? */
bnez t0, .Lsmall_memset\@
- andi t0, a0, STORMASK /* aligned? */
+ andi t0, a0, STORMASK /* aligned? */

#ifdef CONFIG_CPU_MICROMIPS
move t8, a1 /* used by 'swp' instruction */
@@ -103,12 +103,12 @@
#endif
#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
beqz t0, 1f
- PTR_SUBU t0, STORSIZE /* alignment in bytes */
+ PTR_SUBU t0, STORSIZE /* alignment in bytes */
#else
.set noat
li AT, STORSIZE
beqz t0, 1f
- PTR_SUBU t0, AT /* alignment in bytes */
+ PTR_SUBU t0, AT /* alignment in bytes */
.set at
#endif

@@ -149,7 +149,7 @@
1: ori t1, a2, 0x3f /* # of full blocks */
xori t1, 0x3f
beqz t1, .Lmemset_partial\@ /* no block to fill */
- andi t0, a2, 0x40-STORSIZE
+ andi t0, a2, 0x40-STORSIZE

PTR_ADDU t1, a0 /* end address */
.set reorder
@@ -174,7 +174,7 @@
.set at
#endif
jr t1
- PTR_ADDU a0, t0 /* dest ptr */
+ PTR_ADDU a0, t0 /* dest ptr */

.set push
.set noreorder
@@ -186,7 +186,7 @@

beqz a2, 1f
#ifndef CONFIG_CPU_MIPSR6
- PTR_ADDU a0, a2 /* What's left */
+ PTR_ADDU a0, a2 /* What's left */
R10KCBARRIER(0(ra))
#ifdef __MIPSEB__
EX(LONG_S_R, a1, -1(a0), .Llast_fixup\@)
@@ -194,7 +194,7 @@
EX(LONG_S_L, a1, -1(a0), .Llast_fixup\@)
#endif
#else
- PTR_SUBU t0, $0, a2
+ PTR_SUBU t0, $0, a2
PTR_ADDIU t0, 1
STORE_BYTE(0)
STORE_BYTE(1)
@@ -210,11 +210,11 @@
0:
#endif
1: jr ra
- move a2, zero
+ move a2, zero

.Lsmall_memset\@:
beqz a2, 2f
- PTR_ADDU t1, a0, a2
+ PTR_ADDU t1, a0, a2

1: PTR_ADDIU a0, 1 /* fill bytewise */
R10KCBARRIER(0(ra))
@@ -222,7 +222,7 @@
EX(sb, a1, -1(a0), .Lsmall_fixup\@)

2: jr ra /* done */
- move a2, zero
+ move a2, zero
.if __memset == 1
END(memset)
.set __memset, 0
@@ -238,7 +238,7 @@

.Lfirst_fixup\@:
jr ra
- nop
+ nop

.Lfwd_fixup\@:
PTR_L t0, TI_TASK($28)
@@ -246,7 +246,7 @@
LONG_L t0, THREAD_BUADDR(t0)
LONG_ADDU a2, t1
jr ra
- LONG_SUBU a2, t0
+ LONG_SUBU a2, t0

.Lpartial_fixup\@:
PTR_L t0, TI_TASK($28)
@@ -278,7 +278,7 @@
LEAF(memset)
EXPORT_SYMBOL(memset)
beqz a1, 1f
- move v0, a0 /* result */
+ move v0, a0 /* result */

andi a1, 0xff /* spread fillword */
LONG_SLL t1, a1, 8
--
2.7.4