This fix two related bugs:
* PTRACE_GETREGS doesn't get the right orig_ax (syscall) value
* PTRACE_SETREGS can't set the orig_ax value (erased by initial value)
Remove the now useless and error-prone get_syscall().
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Cc: Jeff Dike <redacted>
Cc: Richard Weinberger <richard@nod.at>
Cc: Thomas Gleixner <redacted>
Cc: Kees Cook <redacted>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Will Drewry <wad@chromium.org>
Cc: Thomas Meyer <redacted>
Cc: Nicolas Iooss <redacted>
Cc: Anton Ivanov <redacted>
Cc: linux-kernel@vger.kernel.org
Cc: user-mode-linux-devel@lists.sourceforge.net
Cc: user-mode-linux-user@lists.sourceforge.net
Cc: Meredydd Luff <redacted>
Cc: David Drysdale <redacted>
---
arch/um/kernel/skas/syscall.c | 7 ++++++-
arch/um/os-Linux/skas/process.c | 7 -------
2 files changed, 6 insertions(+), 8 deletions(-)
@@ -16,12 +17,16 @@ void handle_syscall(struct uml_pt_regs *r)longresult;intsyscall;+/* Save the syscall register. */+UPT_SYSCALL_NR(r)=PT_SYSCALL_NR(r->gp);+if(syscall_trace_enter(regs)){result=-ENOSYS;gotoout;}-syscall=get_syscall(r);+/* Get the syscall after being potentially updated with ptrace. */+syscall=UPT_SYSCALL_NR(r);if((syscall>__NR_syscall_max)||syscall<0)result=-ENOSYS;
This brings SECCOMP_MODE_STRICT and SECCOMP_MODE_FILTER support through
prctl(2) and seccomp(2) to User-mode Linux for i386 and x86_64
subarchitectures.
secure_computing() is called first in handle_syscall() so that the
syscall emulation will be aborted quickly if matching a seccomp rule.
This is inspired from Meredydd Luff's patch
(https://gerrit.chromium.org/gerrit/21425).
Signed-off-by: Mickaël Salaün <redacted>
Cc: Jonathan Corbet <redacted>
Cc: Jeff Dike <redacted>
Cc: Richard Weinberger <richard-/L3Ra7n9ekc@public.gmane.org>
Cc: Ingo Molnar <redacted>
Cc: Kees Cook <redacted>
Cc: Andy Lutomirski <redacted>
Cc: Will Drewry <redacted>
Cc: Chris Metcalf <redacted>
Cc: Michael Ellerman <mpe-Gsx/Oe8HsFggBc27wqDAHg@public.gmane.org>
Cc: James Hogan <redacted>
Cc: linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: user-mode-linux-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: user-mode-linux-user-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: Meredydd Luff <redacted>
Cc: David Drysdale <redacted>
---
.../features/seccomp/seccomp-filter/arch-support.txt | 2 +-
arch/um/Kconfig.common | 1 +
arch/um/Kconfig.um | 16 ++++++++++++++++
arch/um/include/asm/thread_info.h | 2 ++
arch/um/kernel/skas/syscall.c | 9 +++++++++
5 files changed, 29 insertions(+), 1 deletion(-)
@@ -20,6 +21,14 @@ void handle_syscall(struct uml_pt_regs *r)/* Save the syscall register. */UPT_SYSCALL_NR(r)=PT_SYSCALL_NR(r->gp);+/* Do the secure computing check first; failures should be fast. */+if(secure_computing()==-1){+/* Do not put secure_computing() into syscall_trace_enter() to+*avoidforcedsyscallreturnvalue.+*/+return;+}+if(syscall_trace_enter(regs)){result=-ENOSYS;gotoout;
From: Richard Weinberger <richard@nod.at> Date: 2015-12-21 00:21:03
Am 21.12.2015 um 01:03 schrieb Mickaël Salaün:
quoted hunk
This fix two related bugs:
* PTRACE_GETREGS doesn't get the right orig_ax (syscall) value
* PTRACE_SETREGS can't set the orig_ax value (erased by initial value)
Remove the now useless and error-prone get_syscall().
Signed-off-by: Mickaël Salaün <redacted>
Cc: Jeff Dike <redacted>
Cc: Richard Weinberger <richard-/L3Ra7n9ekc@public.gmane.org>
Cc: Thomas Gleixner <redacted>
Cc: Kees Cook <redacted>
Cc: Andy Lutomirski <redacted>
Cc: Will Drewry <redacted>
Cc: Thomas Meyer <redacted>
Cc: Nicolas Iooss <redacted>
Cc: Anton Ivanov <redacted>
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: user-mode-linux-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: user-mode-linux-user-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: Meredydd Luff <redacted>
Cc: David Drysdale <redacted>
---
arch/um/kernel/skas/syscall.c | 7 ++++++-
arch/um/os-Linux/skas/process.c | 7 -------
2 files changed, 6 insertions(+), 8 deletions(-)
@@ -16,12 +17,16 @@ void handle_syscall(struct uml_pt_regs *r)longresult;intsyscall;+/* Save the syscall register. */+UPT_SYSCALL_NR(r)=PT_SYSCALL_NR(r->gp);+if(syscall_trace_enter(regs)){result=-ENOSYS;gotoout;}-syscall=get_syscall(r);+/* Get the syscall after being potentially updated with ptrace. */+syscall=UPT_SYSCALL_NR(r);
Doesn't this break the support for changing syscall numbers using PTRACE_SETREGS?
Thanks,
//richard
Some architectures do not implement PTRACE_GETREGSET nor
PTRACE_SETREGSET (required by HAVE_ARCH_TRACEHOOK) but only implement
PTRACE_GETREGS and PTRACE_SETREGS (e.g. User-mode Linux).
This improve seccomp selftest portability for architectures without
HAVE_ARCH_TRACEHOOK support by defining a new trigger HAVE_GETREGS. For
now, this is only enabled for i386 and x86_64 architectures. This is
required to be able to run this tests on User-mode Linux.
Signed-off-by: Mickaël Salaün <redacted>
Cc: Jeff Dike <redacted>
Cc: Richard Weinberger <richard-/L3Ra7n9ekc@public.gmane.org>
Cc: Kees Cook <redacted>
Cc: Andy Lutomirski <redacted>
Cc: Will Drewry <redacted>
Cc: Shuah Khan <redacted>
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: user-mode-linux-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: user-mode-linux-user-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: Meredydd Luff <redacted>
Cc: David Drysdale <redacted>
---
tools/testing/selftests/seccomp/seccomp_bpf.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
@@ -1246,11 +1246,24 @@ TEST_F(TRACE_poke, getpid_runs_normally)# error "Do not know how to find your architecture's registers and syscalls"#endif+/* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for+*architectureswithoutHAVE_ARCH_TRACEHOOK(e.g.User-modeLinux).+*/+#if defined(__x86_64__) || defined(__i386__)+#define HAVE_GETREGS+#endif+/* Architecture-specific syscall fetching routine. */intget_syscall(struct__test_metadata*_metadata,pid_ttracee){-structioveciov;ARCH_REGSregs;+#ifdef HAVE_GETREGS+EXPECT_EQ(0,ptrace(PTRACE_GETREGS,tracee,0,®s)){+TH_LOG("PTRACE_GETREGS failed");+return-1;+}+#else+structioveciov;iov.iov_base=®s;iov.iov_len=sizeof(regs);
@@ -16,12 +17,16 @@ void handle_syscall(struct uml_pt_regs *r)longresult;intsyscall;+/* Save the syscall register. */+UPT_SYSCALL_NR(r)=PT_SYSCALL_NR(r->gp);+if(syscall_trace_enter(regs)){result=-ENOSYS;gotoout;}-syscall=get_syscall(r);+/* Get the syscall after being potentially updated with ptrace. */+syscall=UPT_SYSCALL_NR(r);
Doesn't this break the support for changing syscall numbers using PTRACE_SETREGS?
The logic is unchanged except updating the UPT_SYSCALL_NR before syscall_trace_enter(). I did my last tests with the x86_32 subarchitecture and all tests (from selftest/seccomp), including PTRACE_SETREGS for syscall numbers tests, passed. However, 2 of this tests still fail for x86_64 (only).
No, you chagned the logic.
syscall_trace_enter() enters the ptrace() path, and here EAX/RAX can be changed.
Hence, "syscall = UPT_SYSCALL_NR(r)" will still see the old syscall number.
--> changing syscall numbers got broken by you. :-)
Thanks,
//richard
@@ -16,12 +17,16 @@ void handle_syscall(struct uml_pt_regs *r)longresult;intsyscall;+/* Save the syscall register. */+UPT_SYSCALL_NR(r)=PT_SYSCALL_NR(r->gp);+if(syscall_trace_enter(regs)){result=-ENOSYS;gotoout;}-syscall=get_syscall(r);+/* Get the syscall after being potentially updated with ptrace. */+syscall=UPT_SYSCALL_NR(r);
Doesn't this break the support for changing syscall numbers using PTRACE_SETREGS?
The logic is unchanged except updating the UPT_SYSCALL_NR before syscall_trace_enter(). I did my last tests with the x86_32 subarchitecture and all tests (from selftest/seccomp), including PTRACE_SETREGS for syscall numbers tests, passed. However, 2 of this tests still fail for x86_64 (only).
No, the logic is different.
syscall_trace_enter(regs) enters the ptrace() path and here registers can be changed.
Hence "syscall = UPT_SYSCALL_NR(r);" will see the old syscall number.
UPT_SYSCALL_NR() returns the syscall number before the ptrace() path...
Thanks,
//richard
@@ -16,12 +17,16 @@ void handle_syscall(struct uml_pt_regs *r)longresult;intsyscall;+/* Save the syscall register. */+UPT_SYSCALL_NR(r)=PT_SYSCALL_NR(r->gp);+if(syscall_trace_enter(regs)){result=-ENOSYS;gotoout;}-syscall=get_syscall(r);+/* Get the syscall after being potentially updated with ptrace. */+syscall=UPT_SYSCALL_NR(r);
Doesn't this break the support for changing syscall numbers using PTRACE_SETREGS?
The logic is unchanged except updating the UPT_SYSCALL_NR before syscall_trace_enter(). I did my last tests with the x86_32 subarchitecture and all tests (from selftest/seccomp), including PTRACE_SETREGS for syscall numbers tests, passed. However, 2 of this tests still fail for x86_64 (only).
Regards,
Mickaël
@@ -16,12 +17,16 @@ void handle_syscall(struct uml_pt_regs *r)longresult;intsyscall;+/* Save the syscall register. */+UPT_SYSCALL_NR(r)=PT_SYSCALL_NR(r->gp);+if(syscall_trace_enter(regs)){result=-ENOSYS;gotoout;}-syscall=get_syscall(r);+/* Get the syscall after being potentially updated with ptrace. */+syscall=UPT_SYSCALL_NR(r);
Doesn't this break the support for changing syscall numbers using PTRACE_SETREGS?
The logic is unchanged except updating the UPT_SYSCALL_NR before syscall_trace_enter(). I did my last tests with the x86_32 subarchitecture and all tests (from selftest/seccomp), including PTRACE_SETREGS for syscall numbers tests, passed. However, 2 of this tests still fail for x86_64 (only).
No, the logic is different.
syscall_trace_enter(regs) enters the ptrace() path and here registers can be changed.
Hence "syscall = UPT_SYSCALL_NR(r);" will see the old syscall number.
UPT_SYSCALL_NR() returns the syscall number before the ptrace() path...
The thing is, PTRACE_SETREGS give access to *orig_ax* in the user_regs_struct from arch/x86/include/asm/user_*.h and selftest/seccomp only update this (virtual) register, not the EAX/RAX. Am I missing something?
Mickaël
From: Richard Weinberger <richard@nod.at> Date: 2015-12-21 10:13:44
Am 21.12.2015 um 10:23 schrieb Mickaël Salaün:
quoted
quoted
quoted
Doesn't this break the support for changing syscall numbers using PTRACE_SETREGS?
The logic is unchanged except updating the UPT_SYSCALL_NR before syscall_trace_enter(). I did my last tests with the x86_32 subarchitecture and all tests (from selftest/seccomp), including PTRACE_SETREGS for syscall numbers tests, passed. However, 2 of this tests still fail for x86_64 (only).
No, the logic is different.
syscall_trace_enter(regs) enters the ptrace() path and here registers can be changed.
Hence "syscall = UPT_SYSCALL_NR(r);" will see the old syscall number.
UPT_SYSCALL_NR() returns the syscall number before the ptrace() path...
The thing is, PTRACE_SETREGS give access to *orig_ax* in the user_regs_struct from arch/x86/include/asm/user_*.h and selftest/seccomp only update this (virtual) register, not the EAX/RAX. Am I missing something?
Sorry, meant orig...
Please see the attached program. It proves that your patch is breaking stuff.
The test is extracted from UML's selftests.
Thanks,
//richard
Doesn't this break the support for changing syscall numbers using PTRACE_SETREGS?
The logic is unchanged except updating the UPT_SYSCALL_NR before syscall_trace_enter(). I did my last tests with the x86_32 subarchitecture and all tests (from selftest/seccomp), including PTRACE_SETREGS for syscall numbers tests, passed. However, 2 of this tests still fail for x86_64 (only).
No, the logic is different.
syscall_trace_enter(regs) enters the ptrace() path and here registers can be changed.
Hence "syscall = UPT_SYSCALL_NR(r);" will see the old syscall number.
UPT_SYSCALL_NR() returns the syscall number before the ptrace() path...
The thing is, PTRACE_SETREGS give access to *orig_ax* in the user_regs_struct from arch/x86/include/asm/user_*.h and selftest/seccomp only update this (virtual) register, not the EAX/RAX. Am I missing something?
Sorry, meant orig...
Please see the attached program. It proves that your patch is breaking stuff.
The test is extracted from UML's selftests.
OK, I found the origin of this misunderstanding. On x86_32, PTRACE_SETREGS set regs->syscall when updating orig_eax, which is not the case on x86_64, hence the difference of behavior. I fixed this bug in the v2 series. The ptsc test and all the seccomp tests pass for 32 and 64 bits!
Where can we find the UML selftests?
Thanks,
Mickaël