]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
x86/mm: Only set IBPB when the new thread cannot ptrace current thread
authorKonrad Rzeszutek Wilk <konrad@kernel.org>
Thu, 4 Jan 2018 16:30:05 +0000 (11:30 -0500)
committerKirtikar Kashyap <kirtikar.kashyap@oracle.com>
Fri, 12 Jan 2018 18:19:56 +0000 (10:19 -0800)
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.

Orabug: 27344012
CVE: CVE-2017-5715

Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
[Backport: Need more #include's than the original]

Reviewed-by: John Haxby <john.haxby@oracle.com>
Signed-off-by: Kirtikar Kashyap <kirtikar.kashyap@oracle.com>
arch/x86/include/asm/mmu_context.h
include/linux/ptrace.h
kernel/ptrace.c

index 517c3998d7e44be3fa965916360aac7a73f790bc..a56c610ed8c99ccbacda1c71d1053907a5635fbc 100644 (file)
@@ -4,6 +4,7 @@
 #include <asm/desc.h>
 #include <linux/atomic.h>
 #include <linux/mm_types.h>
+#include <linux/ptrace.h>
 
 #include <trace/events/tlb.h>
 
@@ -98,7 +99,9 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        unsigned cpu = smp_processor_id();
 
-       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 (likely(prev != next)) {
index 998c098dd17211b692526ab5ebfb135fd7e6f7bc..f516c079969c1276fcd6adce90fec6afd03e772a 100644 (file)
@@ -58,12 +58,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
@@ -81,6 +84,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 306928975951571a1bc4543ccd60480a4756ba28..b776ee197cc0ba02b10bfd493ad1d2c856792e08 100644 (file)
@@ -218,9 +218,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;
        int dumpable = 0;
        kuid_t caller_uid;
        kgid_t caller_gid;
@@ -240,7 +241,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) {
@@ -283,7 +284,16 @@ ok:
        }
        rcu_read_unlock();
 
-       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)