diff mbox

[v6,14/21] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

Message ID 1452209679-19445-15-git-send-email-ynorov@caviumnetworks.com (mailing list archive)
State New, archived
Headers show

Commit Message

Yury Norov Jan. 7, 2016, 11:34 p.m. UTC
From: Andrew Pinski <apinski@cavium.com>

Add a separate syscall-table for ILP32, which dispatches either to native
LP64 system call implementation or to compat-syscalls, as appropriate.

Signed-off-by: Andrew Pinski <Andrew.Pinski@caviumnetworks.com>
Signed-off-by: Yury Norov <ynorov@caviumnetworks.com>
---
 arch/arm64/include/asm/unistd.h | 11 ++++++-
 arch/arm64/kernel/Makefile      |  2 +-
 arch/arm64/kernel/entry.S       | 12 +++++++-
 arch/arm64/kernel/sys_ilp32.c   | 66 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 88 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm64/kernel/sys_ilp32.c

Comments

Arnd Bergmann Jan. 8, 2016, 9:04 a.m. UTC | #1
On Friday 08 January 2016 02:34:32 Yury Norov wrote:
> +asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
> +                        unsigned long prot, unsigned long flags,
> +                        unsigned long fd, off_t off);
> +#define sys_mmap2                     sys_mmap
> 

Why do you need a separate declaration for sys_mmap here? There
is one in include/asm-generic/syscalls.h that should be visible
in this file.

	Arnd
Arnd Bergmann Jan. 8, 2016, 9:21 a.m. UTC | #2
On Friday 08 January 2016 02:34:32 Yury Norov wrote:

> @@ -688,6 +692,12 @@ ni_sys:
>  	b	ret_fast_syscall
>  ENDPROC(el0_svc)
>  
> +#ifdef CONFIG_ARM64_ILP32
> +el0_ilp32_svc:
> +	adrp	stbl, sys_call_ilp32_table // load syscall table pointer
> +	b el0_svc_naked
> +#endif

Don't we still need some code that clears the top halves of the 32-bit
arguments? That thread has taken so many turns now that I'm confused
about what we actually need, but I thought we had concluded that your
current approach has at some some problems.

> +#include <asm/syscall.h>
> +
> +#undef __SYSCALL
> +#undef __SC_COMP
> +#undef __SC_3264
> +#undef __SC_COMP_3264

The four #undef are not needed, right?

	Arnd
Yury Norov Jan. 8, 2016, 11:13 a.m. UTC | #3
On Fri, Jan 08, 2016 at 10:21:06AM +0100, Arnd Bergmann wrote:
> On Friday 08 January 2016 02:34:32 Yury Norov wrote:
> 
> > @@ -688,6 +692,12 @@ ni_sys:
> >  	b	ret_fast_syscall
> >  ENDPROC(el0_svc)
> >  
> > +#ifdef CONFIG_ARM64_ILP32
> > +el0_ilp32_svc:
> > +	adrp	stbl, sys_call_ilp32_table // load syscall table pointer
> > +	b el0_svc_naked
> > +#endif
> 
> Don't we still need some code that clears the top halves of the 32-bit
> arguments? That thread has taken so many turns now that I'm confused
> about what we actually need, but I thought we had concluded that your
> current approach has at some some problems.

We are discussing how to do it better - make a generic solution from
s390 with individual syscall handling, or reproduce s390 solution for
ILP32, or zero top-half registers and not use top half of register at
all. As I understand, we stand on 1st option, and agreed to introduce
it separately.

> 
> > +#include <asm/syscall.h>
> > +
> > +#undef __SYSCALL
> > +#undef __SC_COMP
> > +#undef __SC_3264
> > +#undef __SC_COMP_3264
> 
> The four #undef are not needed, right?
> 
> 	Arnd
Arnd Bergmann Jan. 8, 2016, 4:45 p.m. UTC | #4
On Friday 08 January 2016 14:13:18 Yury Norov wrote:
> On Fri, Jan 08, 2016 at 10:21:06AM +0100, Arnd Bergmann wrote:
> > On Friday 08 January 2016 02:34:32 Yury Norov wrote:
> > 
> > > @@ -688,6 +692,12 @@ ni_sys:
> > >     b       ret_fast_syscall
> > >  ENDPROC(el0_svc)
> > >  
> > > +#ifdef CONFIG_ARM64_ILP32
> > > +el0_ilp32_svc:
> > > +   adrp    stbl, sys_call_ilp32_table // load syscall table pointer
> > > +   b el0_svc_naked
> > > +#endif
> > 
> > Don't we still need some code that clears the top halves of the 32-bit
> > arguments? That thread has taken so many turns now that I'm confused
> > about what we actually need, but I thought we had concluded that your
> > current approach has at some some problems.
> 
> We are discussing how to do it better - make a generic solution from
> s390 with individual syscall handling, or reproduce s390 solution for
> ILP32, or zero top-half registers and not use top half of register at
> all. As I understand, we stand on 1st option, and agreed to introduce
> it separately.

Ok. At some point I thought there was a security hole if we don't
do the explicit expansion, but now I can't remember what I was thinking
of or if that was actually real. Let me try to recall my understanding:

We know that the existing DEFINE_SYSCALL wrappers work fine for
32-bit (__u32, int, unsigned int, ...) or smaller (char, short, __u8,
__u16, ...) arguments as well as the explicitly 64-bit arguments (loff_t,
__u64, __s64). Entering a syscall with a 'long' (or size_t, pointer, ...)
argument means that user space expects the kernel to ignore the upper
half, but the kernel will treat it as part of the register. This means
anything we pass into the kernel will follow the ELF ABI for function
calls, and I don't see a security problem here either, just the question
of how the ABI should be defined.

(sorry for the excursion, I needed to write that down to get my own
thoughts sorted)

I still think that the first option from Catalin's email is best here,
and it would be good if you could implement that so we can see if
there are any complications we have not thought of yet.

	Arnd
Yury Norov Jan. 13, 2016, 4:21 p.m. UTC | #5
On Fri, Jan 08, 2016 at 10:21:06AM +0100, Arnd Bergmann wrote:
> On Friday 08 January 2016 02:34:32 Yury Norov wrote:
> 
> > @@ -688,6 +692,12 @@ ni_sys:
> >  	b	ret_fast_syscall
> >  ENDPROC(el0_svc)
> >  
> > +#ifdef CONFIG_ARM64_ILP32
> > +el0_ilp32_svc:
> > +	adrp	stbl, sys_call_ilp32_table // load syscall table pointer
> > +	b el0_svc_naked
> > +#endif
> 
> Don't we still need some code that clears the top halves of the 32-bit
> arguments? That thread has taken so many turns now that I'm confused
> about what we actually need, but I thought we had concluded that your
> current approach has at some some problems.
> 
> > +#include <asm/syscall.h>
> > +
> > +#undef __SYSCALL
> > +#undef __SC_COMP
> > +#undef __SC_3264
> > +#undef __SC_COMP_3264
> 
> The four #undef are not needed, right?
> 
> 	Arnd

No, removing any of them follows compilation problems.
diff mbox

Patch

diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 2971dea..5ea18ef 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -13,9 +13,18 @@ 
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+
+#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_COMPAT_STAT64
+#endif
+
+#ifdef CONFIG_ARM64_ILP32
+#define __ARCH_WANT_COMPAT_SYS_PREADV64
+#define __ARCH_WANT_COMPAT_SYS_PWRITEV64
+#endif
+
 #ifdef CONFIG_AARCH32_EL0
 #define __ARCH_WANT_COMPAT_SYS_GETDENTS64
-#define __ARCH_WANT_COMPAT_STAT64
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_PAUSE
 #define __ARCH_WANT_SYS_GETPGRP
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index ad7158c..a35f2f8 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -28,7 +28,7 @@  $(obj)/%.stub.o: $(obj)/%.o FORCE
 arm64-obj-$(CONFIG_AARCH32_EL0)		+= sys32.o kuser32.o signal32.o 	\
 					   sys_compat.o entry32.o		\
 					   ../../arm/kernel/opcodes.o binfmt_elf32.o
-arm64-obj-$(CONFIG_ARM64_ILP32)		+= binfmt_ilp32.o
+arm64-obj-$(CONFIG_ARM64_ILP32)		+= binfmt_ilp32.o sys_ilp32.o
 arm64-obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o entry-ftrace.o
 arm64-obj-$(CONFIG_MODULES)		+= arm64ksyms.o module.o
 arm64-obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o perf_callchain.o
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 5eb1bb7..f348f58 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -666,9 +666,13 @@  ENDPROC(ret_from_fork)
  */
 	.align	6
 el0_svc:
-	adrp	stbl, sys_call_table		// load syscall table pointer
 	uxtw	scno, w8			// syscall number in w8
 	mov	sc_nr, #__NR_syscalls
+#ifdef CONFIG_ARM64_ILP32
+	ldr	x16, [tsk, #TI_FLAGS]
+	tbnz	x16, #TIF_32BIT_AARCH64, el0_ilp32_svc // We are using ILP32
+#endif
+	adrp	stbl, sys_call_table		// load syscall table pointer
 el0_svc_naked:					// compat entry point
 	stp	x0, scno, [sp, #S_ORIG_X0]	// save the original x0 and syscall number
 	enable_dbg_and_irq
@@ -688,6 +692,12 @@  ni_sys:
 	b	ret_fast_syscall
 ENDPROC(el0_svc)
 
+#ifdef CONFIG_ARM64_ILP32
+el0_ilp32_svc:
+	adrp	stbl, sys_call_ilp32_table // load syscall table pointer
+	b el0_svc_naked
+#endif
+
 	/*
 	 * This is the really slow path.  We're going to be doing context
 	 * switches, and waiting for our parent to respond.
diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c
new file mode 100644
index 0000000..71912b0
--- /dev/null
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -0,0 +1,66 @@ 
+/*
+ * AArch64- ILP32 specific system calls implementation
+ *
+ * Copyright (C) 2016 Cavium Inc.
+ * Author: Andrew Pinski <apinski@cavium.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/msg.h>
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/compat.h>
+
+/* Using non-compat syscalls where necessary */
+#define compat_sys_fadvise64_64        sys_fadvise64_64
+#define compat_sys_fallocate           sys_fallocate
+#define compat_sys_ftruncate64         sys_ftruncate
+#define compat_sys_lookup_dcookie      sys_lookup_dcookie
+#define compat_sys_pread64             sys_pread64
+#define compat_sys_pwrite64            sys_pwrite64
+#define compat_sys_readahead           sys_readahead
+#define compat_sys_shmat               sys_shmat
+#define compat_sys_sync_file_range     sys_sync_file_range
+#define compat_sys_truncate64          sys_truncate
+#define sys_llseek                     sys_lseek
+
+asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
+			 unsigned long prot, unsigned long flags,
+			 unsigned long fd, off_t off);
+#define sys_mmap2		       sys_mmap
+
+#include <asm/syscall.h>
+
+#undef __SYSCALL
+#undef __SC_COMP
+#undef __SC_3264
+#undef __SC_COMP_3264
+
+#define __SYSCALL_COMPAT
+#define __SYSCALL(nr, sym)	[nr] = sym,
+
+/*
+ * The sys_call_ilp32_table array must be 4K aligned to be accessible from
+ * kernel/entry.S.
+ */
+void *sys_call_ilp32_table[__NR_syscalls] __aligned(4096) = {
+	[0 ... __NR_syscalls - 1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};