]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
x86/mm: Only set IBPB when the new thread cannot ptrace current thread
authorTim Chen <tim.c.chen@linux.intel.com>
Tue, 7 Nov 2017 21:52:42 +0000 (13:52 -0800)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Thu, 11 Jan 2018 18:49:43 +0000 (19:49 +0100)
CVE-2017-5753
CVE-2017-5715

To reduce overhead of setting IBPB, we only do that when
the new thread cannot ptrace the current one.  If the new
thread has ptrace capability on current thread, it is safe.

Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Andy Whitcroft <apw@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
arch/x86/mm/tlb.c
include/linux/ptrace.h
kernel/ptrace.c

index bb3ded3a4e5f4553a1d47c930a98de8562bc0270..301e6efbc5141dc903812b60a72887ca5e16a5ca 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/interrupt.h>
 #include <linux/export.h>
 #include <linux/cpu.h>
+#include <linux/ptrace.h>
 
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
@@ -219,7 +220,9 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
                u16 new_asid;
                bool need_flush;
 
-               if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+               /* Null tsk means switching to kernel, so that's safe */
+               if (boot_cpu_has(X86_FEATURE_SPEC_CTRL) && tsk &&
+                       ___ptrace_may_access(tsk, current, PTRACE_MODE_IBPB))
                        native_wrmsrl(MSR_IA32_PRED_CMD, FEATURE_SET_IBPB);
 
                if (IS_ENABLED(CONFIG_VMAP_STACK)) {
index 0e5fcc11b1b8a2441e05d56fcfbe6852e25eb7c1..d6afefd5465b4a4e0965c11b821fc4855a2d15be 100644 (file)
@@ -63,12 +63,15 @@ extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
 #define PTRACE_MODE_NOAUDIT    0x04
 #define PTRACE_MODE_FSCREDS 0x08
 #define PTRACE_MODE_REALCREDS 0x10
+#define PTRACE_MODE_NOACCESS_CHK 0x20
 
 /* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */
 #define PTRACE_MODE_READ_FSCREDS (PTRACE_MODE_READ | PTRACE_MODE_FSCREDS)
 #define PTRACE_MODE_READ_REALCREDS (PTRACE_MODE_READ | PTRACE_MODE_REALCREDS)
 #define PTRACE_MODE_ATTACH_FSCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS)
 #define PTRACE_MODE_ATTACH_REALCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_REALCREDS)
+#define PTRACE_MODE_IBPB (PTRACE_MODE_ATTACH | PTRACE_MODE_NOAUDIT \
+                       | PTRACE_MODE_NOACCESS_CHK | PTRACE_MODE_REALCREDS)
 
 /**
  * ptrace_may_access - check whether the caller is permitted to access
@@ -86,6 +89,9 @@ extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
  */
 extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
 
+extern int ___ptrace_may_access(struct task_struct *cur, struct task_struct *task,
+       unsigned int mode);
+
 static inline int ptrace_reparented(struct task_struct *child)
 {
        return !same_thread_group(child->real_parent, child->parent);
index 60f356d91060c8974268cc5bc02d57c75d359afc..f2f0f1aeabaff18648fee00a03e70d79db114adc 100644 (file)
@@ -268,9 +268,10 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
 }
 
 /* Returns 0 on success, -errno on denial. */
-static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
+int ___ptrace_may_access(struct task_struct *cur, struct task_struct *task,
+               unsigned int mode)
 {
-       const struct cred *cred = current_cred(), *tcred;
+       const struct cred *cred = __task_cred(cur), *tcred;
        struct mm_struct *mm;
        kuid_t caller_uid;
        kgid_t caller_gid;
@@ -290,7 +291,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
         */
 
        /* Don't let security modules deny introspection */
-       if (same_thread_group(task, current))
+       if (same_thread_group(task, cur))
                return 0;
        rcu_read_lock();
        if (mode & PTRACE_MODE_FSCREDS) {
@@ -328,7 +329,16 @@ ok:
             !ptrace_has_cap(mm->user_ns, mode)))
            return -EPERM;
 
-       return security_ptrace_access_check(task, mode);
+       if (!(mode & PTRACE_MODE_NOACCESS_CHK))
+               return security_ptrace_access_check(task, mode);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(___ptrace_may_access);
+
+static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
+{
+       return ___ptrace_may_access(current, task, mode);
 }
 
 bool ptrace_may_access(struct task_struct *task, unsigned int mode)