From f281e194e7dee18134266fa4af926d1f1e5ca208 Mon Sep 17 00:00:00 2001 From: Will Drewry Date: Tue, 22 May 2012 14:54:16 -0500 Subject: [PATCH] arch/x86,asm-generic: add syscall_regs.h asm/syscall.h provides a reliable layer of abstraction for accessing system call-related values across arches. It doesn't come without costs, and using asm/syscall.h values in place of direct struct pt_regs access adds non-trivial overhead. While asm/syscall.h has its place encoding tricky logic, like CONFIG_COMPAT behavior, there are many places where arch-specific code could be moved into a shared location if there were arch-agnostic accessors for the system call register properties. asm/syscall_regs.h provides inline functions which provide direct access to the pt_regs members for the cases where asm/syscall.h doesn't make sense or is too costly. As an example arch/x86/kernel/ptrace.c has been converted to use the macros. The resulting ptrace.o file is the exact same size and contains the exact same output as the pre-patch version. Suggested-by: Al Viro Signed-off-by: Will Drewry --- arch/x86/include/asm/syscall_regs.h | 91 +++++++++++++++++++++++++++++++++++ arch/x86/kernel/ptrace.c | 23 +++++---- include/asm-generic/syscall_regs.h | 76 +++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 arch/x86/include/asm/syscall_regs.h create mode 100644 include/asm-generic/syscall_regs.h diff --git a/arch/x86/include/asm/syscall_regs.h b/arch/x86/include/asm/syscall_regs.h new file mode 100644 index 0000000..68aacf4 --- /dev/null +++ b/arch/x86/include/asm/syscall_regs.h @@ -0,0 +1,91 @@ +/* + * Efficient, uniform access to system call-related registers + * + * Copyright (C) 2012 The Chromium OS Authors + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * See asm-generic/syscall_regs.h for descriptions of what we must do here. + */ + +#ifndef _ASM_X86_SYSCALL_REGS_H +#define _ASM_X86_SYSCALL_REGS_H + +#include + +static inline unsigned long *regs_syscall_nr(struct pt_regs *regs) +{ + return ®s->orig_ax; +} + +static inline unsigned long *regs_syscall_return(struct pt_regs *regs) +{ + /* Note! This does not handle compat mode sign extension, etc */ + return ®s->ax; +} + +static inline unsigned long *regs_syscall32_arg1(struct pt_regs *regs) +{ + return ®s->bx; +} + +static inline unsigned long *regs_syscall32_arg2(struct pt_regs *regs) +{ + return ®s->cx; +} + +static inline unsigned long *regs_syscall32_arg3(struct pt_regs *regs) +{ + return ®s->dx; +} + +static inline unsigned long *regs_syscall32_arg4(struct pt_regs *regs) +{ + return ®s->si; +} + +static inline unsigned long *regs_syscall32_arg5(struct pt_regs *regs) +{ + return ®s->di; +} + +static inline unsigned long *regs_syscall32_arg6(struct pt_regs *regs) +{ + return ®s->bp; +} + +#ifdef CONFIG_X86_64 +static inline unsigned long *regs_syscall64_arg1(struct pt_regs *regs) +{ + return ®s->di; +} + +static inline unsigned long *regs_syscall64_arg2(struct pt_regs *regs) +{ + return ®s->si; +} + +static inline unsigned long *regs_syscall64_arg3(struct pt_regs *regs) +{ + return ®s->dx; +} + +static inline unsigned long *regs_syscall64_arg4(struct pt_regs *regs) +{ + return ®s->r10; +} + +static inline unsigned long *regs_syscall64_arg5(struct pt_regs *regs) +{ + return ®s->r8; +} + +static inline unsigned long *regs_syscall64_arg6(struct pt_regs *regs) +{ + return ®s->r9; +} +#endif /* CONFIG_X86_64 */ + +#endif /* _ASM_X86_SYSCALL_REGS_H */ diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 13474d0..a02ac2a 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "tls.h" @@ -1487,29 +1488,33 @@ long syscall_trace_enter(struct pt_regs *regs) ret = -1L; /* do the secure computing after userspace can't change the syscall. */ - if (!ret && secure_computing(regs->orig_ax)) { + if (!ret && secure_computing(*regs_syscall_nr(regs))) { ret = -1L; goto out; } if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) - trace_sys_enter(regs, regs->orig_ax); + trace_sys_enter(regs, *regs_syscall_nr(regs)); if (IS_IA32) audit_syscall_entry(AUDIT_ARCH_I386, - regs->orig_ax, - regs->bx, regs->cx, - regs->dx, regs->si); + *regs_syscall_nr(regs), + *regs_syscall32_arg1(regs), + *regs_syscall32_arg2(regs), + *regs_syscall32_arg3(regs), + *regs_syscall32_arg4(regs)); #ifdef CONFIG_X86_64 else audit_syscall_entry(AUDIT_ARCH_X86_64, - regs->orig_ax, - regs->di, regs->si, - regs->dx, regs->r10); + *regs_syscall_nr(regs), + *regs_syscall64_arg1(regs), + *regs_syscall64_arg2(regs), + *regs_syscall64_arg3(regs), + *regs_syscall64_arg4(regs)); #endif out: - return ret ?: regs->orig_ax; + return ret ?: syscall_get_nr(current, regs); } void syscall_trace_leave(struct pt_regs *regs) diff --git a/include/asm-generic/syscall_regs.h b/include/asm-generic/syscall_regs.h new file mode 100644 index 0000000..7b3fb5b --- /dev/null +++ b/include/asm-generic/syscall_regs.h @@ -0,0 +1,76 @@ +/* + * Efficient, uniform access to system call-related registers + * + * Copyright (C) 2012 The Chromium OS Authors + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * This file is a stub providing documentation for what functions + * asm-ARCH/syscall_regs.h files need to define. All arch definitions + * should be simple inlines. + * + * All functions are meant to be cross-arch accessors into pt_regs. + * This means that no locks are expected and a populated pt_regs is + * expected. It also means that any per-arch expectations, like + * runtime CONFIG_COMPAT behavior, must be handled by the caller. + * + * See asm/syscall.h for implementations that handle higher level + * runtime logic. + */ + +#ifndef _ASM_X86_SYSCALL_REGS_H +#define _ASM_X86_SYSCALL_REGS_H + +struct pt_regs; + +/** + * regs_syscall_nr - returns a pointer to the system call number entry + * @regs: task_pt_regs() for the targeted task + * + * It's only valid to call this when @regs is known to be populated and + * the caller is the only reader/writer. + */ +static inline unsigned long *regs_syscall_nr(struct pt_regs *regs); + +/** + * regs_syscall_return - returns a pointer to the system call return value entry + * @regs: task_pt_regs() for the targeted task + * + * It's only valid to call this when @regs is known to be populated and + * the caller is the only reader/writer. + */ +static inline unsigned long *regs_syscall_return(struct pt_regs *regs); + +/** + * regs_syscall32_arg1...6 - returns a pointer to the system call arg entry + * @regs: task_pt_regs() for the targeted task + * + * It's only valid to call this when @regs is known to be populated and + * the caller is the only reader/writer. The behavior is undefined if + * these functions are called on non-32-bit system call argument registers. + */ +static inline unsigned long *regs_syscall32_arg1(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg2(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg3(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg4(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg5(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg6(struct pt_regs *regs); + +/** + * regs_syscall64_arg1...6 - returns a pointer to the system call arg entry + * @regs: task_pt_regs() for the targeted task + * + * It's only valid to call this when @regs is known to be populated and + * the caller is the only reader/writer. The behavior is undefined if + * these functions are called on non-32-bit system call argument registers. + */ +static inline unsigned long *regs_syscall32_arg1(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg2(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg3(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg4(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg5(struct pt_regs *regs); +static inline unsigned long *regs_syscall32_arg6(struct pt_regs *regs); + +#endif /* _ASM_X86_SYSCALL_REGS_H */ -- 1.7.9.5