From 6139a8fe0f7ea8cd7b3206acd7bf7d597022e982 Mon Sep 17 00:00:00 2001
From: Andrew Bresticker <abrestic@chromium.org>
Date: Wed, 16 Dec 2015 12:23:53 -0800
Subject: [PATCH] CHROMIUM: x86: alt-syscall: Fix syscall limit check

nr_syscalls and ia32_nr_syscalls are 32-bit values, but a cmpq will do
an 8-byte load resulting in the upper 32-bits being undefined.  Do a
32-bit load of the syscall limit into a temporary register first, and
then do the comparison against RAX (syscall number).

BUG=b:25649436
TEST=security_SandboxLinuxUnittests now passes on x86.

Change-Id: Ia71c7dbb8a08dcc3f9169c5800ca03b8b9f248b8
[abrestic: squashed semenzato@'s fix from CL:319605]
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Signed-off-by: Luigi Semenzato <semenzato@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/321143
---
 arch/x86/ia32/ia32entry.S  | 21 ++++++++++++++-------
 arch/x86/kernel/entry_64.S |  6 ++++--
 2 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index fb9a5fbd6e93c..c43b6759dce2b 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -166,7 +166,8 @@ sysenter_flags_fixed:
 	CFI_REMEMBER_STATE
 	jnz  sysenter_tracesys
 #ifdef CONFIG_ALT_SYSCALL
-	cmpq	TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%rax
+	movl	TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%r11d
+	cmpq	%r11,%rax
 	jae	ia32_badsys
 #else
 	cmpq	$(IA32_NR_syscalls-1),%rax
@@ -217,7 +218,8 @@ sysexit_from_sys_call:
 	call __audit_syscall_entry
 	movl RAX-ARGOFFSET(%rsp),%eax	/* reload syscall number */
 #ifdef CONFIG_ALT_SYSCALL
-	cmpq TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%rax
+	movl TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%r11d
+	cmpq %r11,%rax
 	jae ia32_badsys
 #else
 	cmpq $(IA32_NR_syscalls-1),%rax
@@ -279,7 +281,8 @@ sysenter_tracesys:
 	LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
 	RESTORE_REST
 #ifdef CONFIG_ALT_SYSCALL
-	cmpq	TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%rax
+	movl	TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%r11d
+	cmpq	%r11,%rax
 	jae	int_ret_from_sys_call
 #else
 	cmpq	$(IA32_NR_syscalls-1),%rax
@@ -349,7 +352,8 @@ ENTRY(ia32_cstar_target)
 	CFI_REMEMBER_STATE
 	jnz   cstar_tracesys
 #ifdef CONFIG_ALT_SYSCALL
-	cmpq TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%rax
+	movl TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%r11d
+	cmpq %r11,%rax
 	jae  ia32_badsys
 #else
 	cmpq $IA32_NR_syscalls-1,%rax
@@ -411,7 +415,8 @@ cstar_tracesys:
 	RESTORE_REST
 	xchgl %ebp,%r9d
 #ifdef CONFIG_ALT_SYSCALL
-	cmpq TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%rax
+	movl TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%r11d
+	cmpq %r11,%rax
 	jae int_ret_from_sys_call
 #else
 	cmpq $(IA32_NR_syscalls-1),%rax
@@ -473,7 +478,8 @@ ENTRY(ia32_syscall)
 	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	jnz ia32_tracesys
 #ifdef CONFIG_ALT_SYSCALL
-	cmpq TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%rax
+	movl TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%r11d
+	cmpq %r11,%rax
 	jae ia32_badsys
 #else
 	cmpq $(IA32_NR_syscalls-1),%rax
@@ -502,7 +508,8 @@ ia32_tracesys:
 	LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
 	RESTORE_REST
 #ifdef CONFIG_ALT_SYSCALL
-	cmpq TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%rax
+	movl TI_ia32_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%r11d
+	cmpq %r11,%rax
 	jae  int_ret_from_sys_call
 #else
 	cmpq $(IA32_NR_syscalls-1),%rax
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index bcf21e5ccb2f0..6256714774c99 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -413,7 +413,8 @@ GLOBAL(system_call_after_swapgs)
 system_call_fastpath:
 #if __SYSCALL_MASK == ~0
 # ifdef CONFIG_ALT_SYSCALL
-	cmpq TI_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%rax
+	movl TI_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%r11d
+	cmpq %r11,%rax
 	jae ret_from_sys_call
 # else
 	cmpq $__NR_syscall_max,%rax
@@ -535,7 +536,8 @@ tracesys_phase2:
 	RESTORE_REST
 #if __SYSCALL_MASK == ~0
 # ifdef CONFIG_ALT_SYSCALL
-	cmpq TI_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%rax
+	movl TI_nr_syscalls+THREAD_INFO(%rsp,RIP-ARGOFFSET),%r11d
+	cmpq %r11,%rax
 	jae  int_ret_from_sys_call
 # else
 	cmpq $__NR_syscall_max,%rax