[PATCH AUTOSEL 4.14 23/25] arm/arm64: smccc-1.1: Handle function result as parameters

2018-09-19 Thread Sasha Levin
From: Marc Zyngier 

[ Upstream commit 755a8bf5579d22eb5636685c516d8dede799e27b ]

If someone has the silly idea to write something along those lines:

extern u64 foo(void);

void bar(struct arm_smccc_res *res)
{
arm_smccc_1_1_smc(0xbad, foo(), res);
}

they are in for a surprise, as this gets compiled as:

0588 :
 588:   a9be7bfdstp x29, x30, [sp, #-32]!
 58c:   910003fdmov x29, sp
 590:   f9000bf3str x19, [sp, #16]
 594:   aa0003f3mov x19, x0
 598:   aa1e03e0mov x0, x30
 59c:   9400bl  0 <_mcount>
 5a0:   9400bl  0 
 5a4:   aa0003e1mov x1, x0
 5a8:   d403smc #0x0
 5ac:   b473cbz x19, 5b8 
 5b0:   a9000660stp x0, x1, [x19]
 5b4:   a9010e62stp x2, x3, [x19, #16]
 5b8:   f9400bf3ldr x19, [sp, #16]
 5bc:   a8c27bfdldp x29, x30, [sp], #32
 5c0:   d65f03c0ret
 5c4:   d503201fnop

The call to foo "overwrites" the x0 register for the return value,
and we end up calling the wrong secure service.

A solution is to evaluate all the parameters before assigning
anything to specific registers, leading to the expected result:

0588 :
 588:   a9be7bfdstp x29, x30, [sp, #-32]!
 58c:   910003fdmov x29, sp
 590:   f9000bf3str x19, [sp, #16]
 594:   aa0003f3mov x19, x0
 598:   aa1e03e0mov x0, x30
 59c:   9400bl  0 <_mcount>
 5a0:   9400bl  0 
 5a4:   aa0003e1mov x1, x0
 5a8:   d28175a0mov x0, #0xbad
 5ac:   d403smc #0x0
 5b0:   b473cbz x19, 5bc 
 5b4:   a9000660stp x0, x1, [x19]
 5b8:   a9010e62stp x2, x3, [x19, #16]
 5bc:   f9400bf3ldr x19, [sp, #16]
 5c0:   a8c27bfdldp x29, x30, [sp], #32
 5c4:   d65f03c0ret

Reported-by: Julien Grall 
Signed-off-by: Marc Zyngier 
Signed-off-by: Will Deacon 
Signed-off-by: Sasha Levin 
---
 include/linux/arm-smccc.h | 30 --
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 5a91ff33720b..18863d56273c 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -205,41 +205,51 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, 
unsigned long a1,
register unsigned long r3 asm("r3")
 
 #define __declare_arg_1(a0, a1, res)   \
+   typeof(a1) __a1 = a1;   \
struct arm_smccc_res   *___res = res;   \
register unsigned long r0 asm("r0") = (u32)a0;  \
-   register unsigned long r1 asm("r1") = a1;   \
+   register unsigned long r1 asm("r1") = __a1; \
register unsigned long r2 asm("r2");\
register unsigned long r3 asm("r3")
 
 #define __declare_arg_2(a0, a1, a2, res)   \
+   typeof(a1) __a1 = a1;   \
+   typeof(a2) __a2 = a2;   \
struct arm_smccc_res   *___res = res;   \
register unsigned long r0 asm("r0") = (u32)a0;  \
-   register unsigned long r1 asm("r1") = a1;   \
-   register unsigned long r2 asm("r2") = a2;   \
+   register unsigned long r1 asm("r1") = __a1; \
+   register unsigned long r2 asm("r2") = __a2; \
register unsigned long r3 asm("r3")
 
 #define __declare_arg_3(a0, a1, a2, a3, res)   \
+   typeof(a1) __a1 = a1;   \
+   typeof(a2) __a2 = a2;   \
+   typeof(a3) __a3 = a3;   \
struct arm_smccc_res   *___res = res;   \
register unsigned long r0 asm("r0") = (u32)a0;  \
-   register unsigned long r1 asm("r1") = a1;   \
-   register unsigned long r2 asm("r2") = a2;   \
-   register unsigned long r3 asm("r3") = a3
+   register unsigned long r1 asm("r1") = __a1; \
+   register unsigned long r2 asm("r2") = __a2; \
+   register unsigned long r3 asm("r3") = __a3
 
 #define __declare_arg_4(a0, a1, a2, a3, a4, res)   \

[PATCH AUTOSEL 4.14 23/25] arm/arm64: smccc-1.1: Handle function result as parameters

2018-09-19 Thread Sasha Levin
From: Marc Zyngier 

[ Upstream commit 755a8bf5579d22eb5636685c516d8dede799e27b ]

If someone has the silly idea to write something along those lines:

extern u64 foo(void);

void bar(struct arm_smccc_res *res)
{
arm_smccc_1_1_smc(0xbad, foo(), res);
}

they are in for a surprise, as this gets compiled as:

0588 :
 588:   a9be7bfdstp x29, x30, [sp, #-32]!
 58c:   910003fdmov x29, sp
 590:   f9000bf3str x19, [sp, #16]
 594:   aa0003f3mov x19, x0
 598:   aa1e03e0mov x0, x30
 59c:   9400bl  0 <_mcount>
 5a0:   9400bl  0 
 5a4:   aa0003e1mov x1, x0
 5a8:   d403smc #0x0
 5ac:   b473cbz x19, 5b8 
 5b0:   a9000660stp x0, x1, [x19]
 5b4:   a9010e62stp x2, x3, [x19, #16]
 5b8:   f9400bf3ldr x19, [sp, #16]
 5bc:   a8c27bfdldp x29, x30, [sp], #32
 5c0:   d65f03c0ret
 5c4:   d503201fnop

The call to foo "overwrites" the x0 register for the return value,
and we end up calling the wrong secure service.

A solution is to evaluate all the parameters before assigning
anything to specific registers, leading to the expected result:

0588 :
 588:   a9be7bfdstp x29, x30, [sp, #-32]!
 58c:   910003fdmov x29, sp
 590:   f9000bf3str x19, [sp, #16]
 594:   aa0003f3mov x19, x0
 598:   aa1e03e0mov x0, x30
 59c:   9400bl  0 <_mcount>
 5a0:   9400bl  0 
 5a4:   aa0003e1mov x1, x0
 5a8:   d28175a0mov x0, #0xbad
 5ac:   d403smc #0x0
 5b0:   b473cbz x19, 5bc 
 5b4:   a9000660stp x0, x1, [x19]
 5b8:   a9010e62stp x2, x3, [x19, #16]
 5bc:   f9400bf3ldr x19, [sp, #16]
 5c0:   a8c27bfdldp x29, x30, [sp], #32
 5c4:   d65f03c0ret

Reported-by: Julien Grall 
Signed-off-by: Marc Zyngier 
Signed-off-by: Will Deacon 
Signed-off-by: Sasha Levin 
---
 include/linux/arm-smccc.h | 30 --
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 5a91ff33720b..18863d56273c 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -205,41 +205,51 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, 
unsigned long a1,
register unsigned long r3 asm("r3")
 
 #define __declare_arg_1(a0, a1, res)   \
+   typeof(a1) __a1 = a1;   \
struct arm_smccc_res   *___res = res;   \
register unsigned long r0 asm("r0") = (u32)a0;  \
-   register unsigned long r1 asm("r1") = a1;   \
+   register unsigned long r1 asm("r1") = __a1; \
register unsigned long r2 asm("r2");\
register unsigned long r3 asm("r3")
 
 #define __declare_arg_2(a0, a1, a2, res)   \
+   typeof(a1) __a1 = a1;   \
+   typeof(a2) __a2 = a2;   \
struct arm_smccc_res   *___res = res;   \
register unsigned long r0 asm("r0") = (u32)a0;  \
-   register unsigned long r1 asm("r1") = a1;   \
-   register unsigned long r2 asm("r2") = a2;   \
+   register unsigned long r1 asm("r1") = __a1; \
+   register unsigned long r2 asm("r2") = __a2; \
register unsigned long r3 asm("r3")
 
 #define __declare_arg_3(a0, a1, a2, a3, res)   \
+   typeof(a1) __a1 = a1;   \
+   typeof(a2) __a2 = a2;   \
+   typeof(a3) __a3 = a3;   \
struct arm_smccc_res   *___res = res;   \
register unsigned long r0 asm("r0") = (u32)a0;  \
-   register unsigned long r1 asm("r1") = a1;   \
-   register unsigned long r2 asm("r2") = a2;   \
-   register unsigned long r3 asm("r3") = a3
+   register unsigned long r1 asm("r1") = __a1; \
+   register unsigned long r2 asm("r2") = __a2; \
+   register unsigned long r3 asm("r3") = __a3
 
 #define __declare_arg_4(a0, a1, a2, a3, a4, res)   \