From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1765754AbcINVIc (ORCPT ); Wed, 14 Sep 2016 17:08:32 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:34531 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1765704AbcINVI1 (ORCPT ); Wed, 14 Sep 2016 17:08:27 -0400 From: Kyle Huey X-Google-Original-From: Kyle Huey To: "Robert O'Callahan" Cc: linux-kernel@vger.kernel.org, Borislav Petkov , Andy Lutomirski , Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , x86@kernel.org (maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT)), Al Viro , Milosz Tanski , "Dmitry V. Levin" , David Howells , Zach Brown , Eric B Munson , Peter Zijlstra , Jiri Slaby , "Michael S. Tsirkin" , Andrey Ryabinin , Paul Gortmaker , Borislav Petkov , Dmitry Vyukov , Dmitry Safonov , Mateusz Guzik Subject: [RESEND][PATCH v2 1/3] syscalls,x86 Expose arch_prctl on x86-32. Date: Wed, 14 Sep 2016 14:08:09 -0700 Message-Id: <1473887291-18384-2-git-send-email-khuey@kylehuey.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1473887291-18384-1-git-send-email-khuey@kylehuey.com> References: <1473887291-18384-1-git-send-email-khuey@kylehuey.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Signed-off-by: Kyle Huey --- arch/x86/entry/syscalls/syscall_32.tbl | 1 + arch/x86/kernel/process.c | 80 ++++++++++++++++++++++++++++++++++ arch/x86/kernel/process_64.c | 66 ---------------------------- 3 files changed, 81 insertions(+), 66 deletions(-) diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index f848572..3b6965b 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -386,3 +386,4 @@ 377 i386 copy_file_range sys_copy_file_range 378 i386 preadv2 sys_preadv2 compat_sys_preadv2 379 i386 pwritev2 sys_pwritev2 compat_sys_pwritev2 +380 i386 arch_prctl sys_arch_prctl diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 62c0b0e..0f857c3 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include /* * per-CPU TSS segments. Threads are completely 'soft' on Linux, @@ -567,3 +569,81 @@ unsigned long get_wchan(struct task_struct *p) } while (count++ < 16 && p->state != TASK_RUNNING); return 0; } + +long do_arch_prctl(struct task_struct *task, int code, unsigned long arg2) +{ + int ret = 0; + int doit = task == current; + int is_32 = IS_ENABLED(CONFIG_IA32_EMULATION) && test_thread_flag(TIF_IA32); + int cpu; + + switch (code) { +#ifdef CONFIG_X86_64 + case ARCH_SET_GS: + if (is_32) + return -EINVAL; + if (arg2 >= TASK_SIZE_MAX) + return -EPERM; + cpu = get_cpu(); + task->thread.gsindex = 0; + task->thread.gsbase = arg2; + if (doit) { + load_gs_index(0); + ret = wrmsrl_safe(MSR_KERNEL_GS_BASE, arg2); + } + put_cpu(); + break; + case ARCH_SET_FS: + if (is_32) + return -EINVAL; + /* Not strictly needed for fs, but do it for symmetry + with gs */ + if (arg2 >= TASK_SIZE_MAX) + return -EPERM; + cpu = get_cpu(); + task->thread.fsindex = 0; + task->thread.fsbase = arg2; + if (doit) { + /* set the selector to 0 to not confuse __switch_to */ + loadsegment(fs, 0); + ret = wrmsrl_safe(MSR_FS_BASE, arg2); + } + put_cpu(); + break; + case ARCH_GET_FS: { + unsigned long base; + + if (is_32) + return -EINVAL; + if (doit) + rdmsrl(MSR_FS_BASE, base); + else + base = task->thread.fsbase; + ret = put_user(base, (unsigned long __user *)arg2); + break; + } + case ARCH_GET_GS: { + unsigned long base; + + if (is_32) + return -EINVAL; + if (doit) + rdmsrl(MSR_KERNEL_GS_BASE, base); + else + base = task->thread.gsbase; + ret = put_user(base, (unsigned long __user *)arg2); + break; + } +#endif + default: + ret = -EINVAL; + break; + } + + return ret; +} + +SYSCALL_DEFINE2(arch_prctl, int, code, unsigned long, arg2) +{ + return do_arch_prctl(current, code, arg2); +} diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 63236d8..e8c6302 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -524,72 +524,6 @@ void set_personality_ia32(bool x32) } EXPORT_SYMBOL_GPL(set_personality_ia32); -long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) -{ - int ret = 0; - int doit = task == current; - int cpu; - - switch (code) { - case ARCH_SET_GS: - if (addr >= TASK_SIZE_MAX) - return -EPERM; - cpu = get_cpu(); - task->thread.gsindex = 0; - task->thread.gsbase = addr; - if (doit) { - load_gs_index(0); - ret = wrmsrl_safe(MSR_KERNEL_GS_BASE, addr); - } - put_cpu(); - break; - case ARCH_SET_FS: - /* Not strictly needed for fs, but do it for symmetry - with gs */ - if (addr >= TASK_SIZE_MAX) - return -EPERM; - cpu = get_cpu(); - task->thread.fsindex = 0; - task->thread.fsbase = addr; - if (doit) { - /* set the selector to 0 to not confuse __switch_to */ - loadsegment(fs, 0); - ret = wrmsrl_safe(MSR_FS_BASE, addr); - } - put_cpu(); - break; - case ARCH_GET_FS: { - unsigned long base; - if (doit) - rdmsrl(MSR_FS_BASE, base); - else - base = task->thread.fsbase; - ret = put_user(base, (unsigned long __user *)addr); - break; - } - case ARCH_GET_GS: { - unsigned long base; - if (doit) - rdmsrl(MSR_KERNEL_GS_BASE, base); - else - base = task->thread.gsbase; - ret = put_user(base, (unsigned long __user *)addr); - break; - } - - default: - ret = -EINVAL; - break; - } - - return ret; -} - -long sys_arch_prctl(int code, unsigned long addr) -{ - return do_arch_prctl(current, code, addr); -} - unsigned long KSTK_ESP(struct task_struct *task) { return task_pt_regs(task)->sp; -- 2.7.4