diff mbox

[1/2] arm64: Add seccomp support

Message ID 1391767892-5395-2-git-send-email-takahiro.akashi@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

AKASHI Takahiro Feb. 7, 2014, 10:11 a.m. UTC
secure_computing() should always be called first in syscall_trace(), and
if it returns non-zero, we should stop further handling. Then that system
call may eventually fail, be trapped or the process itself be killed
depending on loaded rules.

This patch also defines specific system call numbers, __NR_seccomp_*,
solely used by secure_computing() for seccomp mode 1 (only read, write, exit
and sigreturn are allowd).

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 arch/arm64/Kconfig               |   17 +++++++++++++++++
 arch/arm64/include/asm/seccomp.h |   28 ++++++++++++++++++++++++++++
 arch/arm64/include/asm/unistd.h  |    3 +++
 arch/arm64/kernel/entry.S        |    4 ++++
 arch/arm64/kernel/ptrace.c       |    5 +++++
 5 files changed, 57 insertions(+)
 create mode 100644 arch/arm64/include/asm/seccomp.h

Comments

Arnd Bergmann Feb. 7, 2014, 2:44 p.m. UTC | #1
On Friday 07 February 2014 19:11:31 AKASHI Takahiro wrote:
> diff --git a/arch/arm64/include/asm/seccomp.h b/arch/arm64/include/asm/seccomp.h
> new file mode 100644
> index 0000000..3482155
> --- /dev/null
> +++ b/arch/arm64/include/asm/seccomp.h
> @@ -0,0 +1,28 @@
> +/*
> + * arch/arm64/include/asm/seccomp.h
> + *
> + * Copyright (C) 2014 Linaro Limited
> + * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> + *
> + * 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.
> + */
> +#ifndef _ASM_SECCOMP_H
> +#define _ASM_SECCOMP_H
> +
> +#include <asm/unistd.h>
> +
> +#ifdef CONFIG_COMPAT
> +#define __NR_seccomp_read_32           __NR_compat_read
> +#define __NR_seccomp_write_32          __NR_compat_write
> +#define __NR_seccomp_exit_32           __NR_compat_exit
> +#define __NR_seccomp_sigreturn_32      __NR_compat_sigreturn
> +#endif /* CONFIG_COMPAT */
> +
> +#define __NR_seccomp_read              __NR_read
> +#define __NR_seccomp_write             __NR_write
> +#define __NR_seccomp_exit              __NR_exit
> +#define __NR_seccomp_sigreturn         __NR_rt_sigreturn
> +
> +#endif /* _ASM_SECCOMP_H */
> 

This file looks extremely generic and can be shared by every
architecture other than MIPS for all I can tell.

Please add it to include/asm-generic instead of arch/arm64,
and add a line to arch/arm64/include/asm/Kbuild.

	Arnd
Arnd Bergmann Feb. 12, 2014, 11:05 a.m. UTC | #2
On Wednesday 12 February 2014, Takahiro Akashi wrote:
> Thank you for your comment.
> I'm afraid that I can't do so because how compat syscall numbers
> are named varies from arch to arch. __NR_compat_read is used
> only on arm64, while __NR_ia32_read on x86. On other archs,
> __NR_read is common to 32-bit and 64-bit tasks.

It's fine, I'm the maintainer for asm-generic ;-)

All future architectures are required to do it the same way as
arm64 and use the generic syscall ABI. It just means we won't be
able to share this header with x86 or other architectures that
use a nonstandard string. We should have it in the generic place
even if arm64 is the only user for now.

	Arnd
Arnd Bergmann Feb. 12, 2014, 11:17 a.m. UTC | #3
On Wednesday 12 February 2014, Arnd Bergmann wrote:
> 
> On Wednesday 12 February 2014, Takahiro Akashi wrote:
> > Thank you for your comment.
> > I'm afraid that I can't do so because how compat syscall numbers
> > are named varies from arch to arch. __NR_compat_read is used
> > only on arm64, while __NR_ia32_read on x86. On other archs,
> > __NR_read is common to 32-bit and 64-bit tasks.
> 
> It's fine, I'm the maintainer for asm-generic ;-)
> 
> All future architectures are required to do it the same way as
> arm64 and use the generic syscall ABI. It just means we won't be
> able to share this header with x86 or other architectures that
> use a nonstandard string. We should have it in the generic place
> even if arm64 is the only user for now.
> 

Ok, I was wrong. The generic header file should only be used for
architectures on which both ABIs use the generic syscall numbers,
and arm64 obviously doesn't do that for arm32 compatibility.

The proper generic header file should contain

#if defined(CONFIG_COMPAT) && !defined(__NR_seccomp_read_32)
#define __NR_seccomp_read_32           __NR_read
#define __NR_seccomp_write_32          __NR_write
#define __NR_seccomp_exit_32           __NR_exit
#define __NR_seccomp_sigreturn_32      __NR_rt_sigreturn
#endif /* CONFIG_COMPAT && ! already defined */

#define __NR_seccomp_read              __NR_read
#define __NR_seccomp_write             __NR_write
#define __NR_seccomp_exit              __NR_exit
#define __NR_seccomp_sigreturn         __NR_rt_sigreturn

and then have arm64 override the first four by defining its
own. I would still prefer having it done this way, but it actually
doesn't gain us that much since this default wouldn't work on
any 64-bit architecture currently implementing seccomp. I'll leave
it up to you whether you want to do it or not.

	Arnd
Catalin Marinas Feb. 18, 2014, 3:38 p.m. UTC | #4
On Fri, Feb 07, 2014 at 10:11:31AM +0000, AKASHI Takahiro wrote:
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -26,6 +26,7 @@
>  #include <linux/smp.h>
>  #include <linux/ptrace.h>
>  #include <linux/user.h>
> +#include <linux/seccomp.h>
>  #include <linux/security.h>
>  #include <linux/init.h>
>  #include <linux/signal.h>
> @@ -1064,6 +1065,10 @@ asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
>  {
>  	unsigned long saved_reg;
>  
> +	if (!dir && secure_computing((int)regs->syscallno))
> +		/* seccomp failures shouldn't expose any additional code. */
> +		return -1;

That's only restricted to the arm64 code but could we use a more
meaningful error number?
AKASHI Takahiro Feb. 19, 2014, 11:39 a.m. UTC | #5
On 02/19/2014 12:38 AM, Catalin Marinas wrote:
> On Fri, Feb 07, 2014 at 10:11:31AM +0000, AKASHI Takahiro wrote:
>> --- a/arch/arm64/kernel/ptrace.c
>> +++ b/arch/arm64/kernel/ptrace.c
>> @@ -26,6 +26,7 @@
>>   #include <linux/smp.h>
>>   #include <linux/ptrace.h>
>>   #include <linux/user.h>
>> +#include <linux/seccomp.h>
>>   #include <linux/security.h>
>>   #include <linux/init.h>
>>   #include <linux/signal.h>
>> @@ -1064,6 +1065,10 @@ asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
>>   {
>>   	unsigned long saved_reg;
>>
>> +	if (!dir && secure_computing((int)regs->syscallno))
>> +		/* seccomp failures shouldn't expose any additional code. */
>> +		return -1;
>
> That's only restricted to the arm64 code but could we use a more
> meaningful error number?

Other architectures, including arm, also return just -1 in syscall_trace_enter(),
but of course, we can use another value, say, -EPERM or -ENOSYS?

-Takahiro AKASHI
Catalin Marinas Feb. 19, 2014, 4:41 p.m. UTC | #6
On Wed, Feb 19, 2014 at 11:39:09AM +0000, AKASHI Takahiro wrote:
> On 02/19/2014 12:38 AM, Catalin Marinas wrote:
> > On Fri, Feb 07, 2014 at 10:11:31AM +0000, AKASHI Takahiro wrote:
> >> --- a/arch/arm64/kernel/ptrace.c
> >> +++ b/arch/arm64/kernel/ptrace.c
> >> @@ -26,6 +26,7 @@
> >>   #include <linux/smp.h>
> >>   #include <linux/ptrace.h>
> >>   #include <linux/user.h>
> >> +#include <linux/seccomp.h>
> >>   #include <linux/security.h>
> >>   #include <linux/init.h>
> >>   #include <linux/signal.h>
> >> @@ -1064,6 +1065,10 @@ asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
> >>   {
> >>   	unsigned long saved_reg;
> >>
> >> +	if (!dir && secure_computing((int)regs->syscallno))
> >> +		/* seccomp failures shouldn't expose any additional code. */
> >> +		return -1;
> >
> > That's only restricted to the arm64 code but could we use a more
> > meaningful error number?
> 
> Other architectures, including arm, also return just -1 in syscall_trace_enter(),
> but of course, we can use another value, say, -EPERM or -ENOSYS?

Actually we have another case of setting regs->syscallno = ~0UL in the
same function, so we could do the same (also in line with entry.S).
AKASHI Takahiro Feb. 20, 2014, 12:34 a.m. UTC | #7
On 02/20/2014 01:41 AM, Catalin Marinas wrote:
> On Wed, Feb 19, 2014 at 11:39:09AM +0000, AKASHI Takahiro wrote:
>> On 02/19/2014 12:38 AM, Catalin Marinas wrote:
>>> On Fri, Feb 07, 2014 at 10:11:31AM +0000, AKASHI Takahiro wrote:
>>>> --- a/arch/arm64/kernel/ptrace.c
>>>> +++ b/arch/arm64/kernel/ptrace.c
>>>> @@ -26,6 +26,7 @@
>>>>    #include <linux/smp.h>
>>>>    #include <linux/ptrace.h>
>>>>    #include <linux/user.h>
>>>> +#include <linux/seccomp.h>
>>>>    #include <linux/security.h>
>>>>    #include <linux/init.h>
>>>>    #include <linux/signal.h>
>>>> @@ -1064,6 +1065,10 @@ asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
>>>>    {
>>>>    	unsigned long saved_reg;
>>>>
>>>> +	if (!dir && secure_computing((int)regs->syscallno))
>>>> +		/* seccomp failures shouldn't expose any additional code. */
>>>> +		return -1;
>>>
>>> That's only restricted to the arm64 code but could we use a more
>>> meaningful error number?
>>
>> Other architectures, including arm, also return just -1 in syscall_trace_enter(),
>> but of course, we can use another value, say, -EPERM or -ENOSYS?
>
> Actually we have another case of setting regs->syscallno = ~0UL in the
> same function, so we could do the same (also in line with entry.S).

I believe that I got you now, but we need to distinguish failure case of
seccomp and the existing (~0UL) case. In former case, depending on a bpf
rule loaded into the kernel, errno may be assigned to any arbitrary number
(not necessarily ENOSYS).
So I will use another value for this specific seccomp case.

Thanks,
-Takahiro AKASHI
diff mbox

Patch

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index a21455e..a0102f7 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -27,6 +27,7 @@  config ARM64
 	select HARDIRQS_SW_RESEND
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_JUMP_LABEL
+	select HAVE_ARCH_SECCOMP_FILTER
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_DEBUG_BUGVERBOSE
 	select HAVE_DEBUG_KMEMLEAK
@@ -222,6 +223,22 @@  config HAVE_ARCH_TRANSPARENT_HUGEPAGE
 
 source "mm/Kconfig"
 
+config SECCOMP
+	def_bool y
+	prompt "Enable seccomp to safely compute untrusted bytecode"
+	---help---
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via prctl(PR_SET_SECCOMP), it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
+	  If unsure, say Y. Only embedded should say N here.
+
 config XEN_DOM0
 	def_bool y
 	depends on XEN
diff --git a/arch/arm64/include/asm/seccomp.h b/arch/arm64/include/asm/seccomp.h
new file mode 100644
index 0000000..3482155
--- /dev/null
+++ b/arch/arm64/include/asm/seccomp.h
@@ -0,0 +1,28 @@ 
+/*
+ * arch/arm64/include/asm/seccomp.h
+ *
+ * Copyright (C) 2014 Linaro Limited
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *
+ * 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.
+ */
+#ifndef _ASM_SECCOMP_H
+#define _ASM_SECCOMP_H
+
+#include <asm/unistd.h>
+
+#ifdef CONFIG_COMPAT
+#define __NR_seccomp_read_32		__NR_compat_read
+#define __NR_seccomp_write_32		__NR_compat_write
+#define __NR_seccomp_exit_32		__NR_compat_exit
+#define __NR_seccomp_sigreturn_32	__NR_compat_sigreturn
+#endif /* CONFIG_COMPAT */
+
+#define __NR_seccomp_read		__NR_read
+#define __NR_seccomp_write		__NR_write
+#define __NR_seccomp_exit		__NR_exit
+#define __NR_seccomp_sigreturn		__NR_rt_sigreturn
+
+#endif /* _ASM_SECCOMP_H */
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 4a09fdb..05f2db3 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -30,6 +30,9 @@ 
  * Compat syscall numbers used by the AArch64 kernel.
  */
 #define __NR_compat_restart_syscall	0
+#define __NR_compat_exit		1
+#define __NR_compat_read		3
+#define __NR_compat_write		4
 #define __NR_compat_sigreturn		119
 #define __NR_compat_rt_sigreturn	173
 
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 96c2d03..55d4e6c 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -651,6 +651,10 @@  __sys_trace:
 	mov	x1, sp
 	mov	w0, #0				// trace entry
 	bl	syscall_trace
+#ifdef CONFIG_SECCOMP
+	cmp	w0, #0				// check seccomp result
+	b.lt	ret_to_user			// -1 means 'rejected'
+#endif
 	adr	lr, __sys_trace_return		// return address
 	uxtw	scno, w0			// syscall number (possibly new)
 	mov	x1, sp				// pointer to regs
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 8cdba09..3bfe398 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -26,6 +26,7 @@ 
 #include <linux/smp.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/seccomp.h>
 #include <linux/security.h>
 #include <linux/init.h>
 #include <linux/signal.h>
@@ -1064,6 +1065,10 @@  asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
 {
 	unsigned long saved_reg;
 
+	if (!dir && secure_computing((int)regs->syscallno))
+		/* seccomp failures shouldn't expose any additional code. */
+		return -1;
+
 	if (is_compat_task()) {
 		/* AArch32 uses ip (r12) for scratch */
 		saved_reg = regs->regs[12];