Web lists-archives.com

[PATCH] ARM: Fix oops at csum_and_copy_from_user()




From: "seokjoo.lee" <seokjoo.lee@xxxxxxx>

fix code corruption by fixup part of csum_partial_copy_from_user()
due to invalid stack offset of err_ptr for CONFIG_CPU_SW_DOMAIN_PAN.

For a kernel built for arm architecture with CONFIG_CPU_SW_DOMAIN_PAN,
if an application calls 'sendto' with *invalid parameter* which might
cause fault within csum_paritial_copy_from_user, then the fixup part of
csum_partial_copy_from_user try to overwrite code area stored at 'lr'.
Then, kernel generates oops with undefined instruction 0xfffffff2 at
csum_and_copy_from_iter triggered from the next 'sendto' call.
This behavior is not gracefully returning *err_ptr with -EFAULT value as
designed.

Originally 'save_regs' macro stores 8 registers - (r1, r2, r4 - r8, lr)
and the err_ptr was passed at '[sp, #8*4]'.
Since commit a5e090acbf54 ("ARM: software-based priviledged-no-access
support") introducing CONFIG_CPU_SW_DOMAIN_PAN, this bug lurks in fixup
part below the screen.
If CONFIG_CPU_SW_DOMAIN_PAN is defined, the 'save_regs' macro stores 9
registers - '(r1, r2, r4 - r8, ip, lr)' into stack and the err_ptr is
passed at '[sp, #9*4]' instead of '[sp, #8*4]' because of 'ip' register
adopted to save value of Domain Access Control register.
After then, fault handling mechanism triggered by *invalid parameter*
jumps into fixup part of csum_paritial_copy_from_user, regardlessly
stores -EFAULT value to [[sp, #8*4]] which is actually '[lr]'. Finally,
this try to overwrite caller of 'csum_partial_copy_from_user', i.e.
'csum_and_copy_from_iter' - as 0xfffffff2.

Fix by defining ERR_PTR_OFFSET properly within #if block near
'save_regs/load_regs' pair to reduce the chance of mistake, and
by replacing the constant 8 in fixup part with ERR_PTR_OFFSET to deal
with CONFIG_CPU_SW_DOMAIN_PAN.

---
A kernel with CONFIG_CPU_SW_DOMAIN_PAN produces panic as follows.

Internal error: Oops - undefined instruction: 0 [#1] PREEMPT SMP ARM
CPU: 3 PID: 2685 Comm: connmand Tainted: P           O    4.4.3-132 #1
Hardware name: LG Electronics DTV SoC
task: ab7cc200 ti: bbb40000 task.ti: bbb40000
PC is at csum_and_copy_from_iter+0x140/0x50c
LR is at csum_and_copy_from_iter+0x140/0x50c
pc : [<803b2148>]    lr : [<803b2148>]    psr: 40010013
sp : bbb41c90  ip : 00000051  fp : 00000000
r10: 00000028  r9 : b4921c2c  r8 : b4921c24
r7 : bbb41ee4  r6 : 00000000  r5 : 00000028  r4 : bbb41ef4
r3 : 00000000  r2 : 00000028  r1 : b4921c2c  r0 : 00000000
.....
Flags: nZcv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
Control: 10c5383d  Table: 3b64806a  DAC: 00000051
[<803b2148>] (csum_and_copy_from_iter) from [<80a9aebc>] (ip_generic_getfrag+0x3c/0xc0)
[<80a9aebc>] (ip_generic_getfrag) from [<80a9ac0c>] (__ip_append_data+0x7c8/0x9dc)
[<80a9ac0c>] (__ip_append_data) from [<80a9c730>] (ip_make_skb+0xb0/0xec)
[<80a9c730>] (ip_make_skb) from [<80ac3a4c>] (udp_sendmsg+0x270/0x828)
[<80ac3a4c>] (udp_sendmsg) from [<80a43a8c>] (sock_sendmsg+0x14/0x24)
[<80a43a8c>] (sock_sendmsg) from [<80a44ec8>] (SyS_sendto+0xb4/0xe8)
[<80a44ec8>] (SyS_sendto) from [<80090280>] (ret_fast_syscall+0x0/0x3c)
Code: e58d2000 e1a01009 e1a02005 ebffad40 (fffffff2)
---[ end trace 6870c0e483440b32 ]---

Signed-off-by: Seokjoo Lee <seokjoo.lee@xxxxxxx>
Signed-off-by: Jaeguk Lee <jaeguk.lee@xxxxxxx>
Cc: Jongsung Kim <neidhard.kim@xxxxxxx>
Cc: Chanho Min <chanho.min@xxxxxxx>
---
 arch/arm/lib/csumpartialcopyuser.S | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S
index 1712f13..0772bce 100644
--- a/arch/arm/lib/csumpartialcopyuser.S
+++ b/arch/arm/lib/csumpartialcopyuser.S
@@ -29,6 +29,7 @@
 		mcr	p15, 0, ip, c3, c0, 0
 		ret	lr
 		.endm
+#define ERR_PTR_OFFSET 9
 #else
 		.macro	save_regs
 		stmfd	sp!, {r1, r2, r4 - r8, lr}
@@ -37,6 +38,7 @@
 		.macro	load_regs
 		ldmfd	sp!, {r1, r2, r4 - r8, pc}
 		.endm
+#define ERR_PTR_OFFSET 8
 #endif
 
 		.macro	load1b,	reg1
@@ -85,7 +87,7 @@
 		.pushsection .text.fixup,"ax"
 		.align	4
 9001:		mov	r4, #-EFAULT
-		ldr	r5, [sp, #8*4]		@ *err_ptr
+		ldr	r5, [sp, #ERR_PTR_OFFSET*4]		@ *err_ptr
 		str	r4, [r5]
 		ldmia	sp, {r1, r2}		@ retrieve dst, len
 		add	r2, r2, r1
-- 
2.7.4